Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

To obtain record number from reading of fpt file

29 views
Skip to first unread message
Message has been deleted

Marco Boschi

unread,
Aug 9, 2010, 5:46:16 AM8/9/10
to
#include "FileIO.ch"

FUNCTION MAIN()

LOCAL cAllMemos

// open and read all dbf file into cStringa variable
nHandle := FOPEN( "memo2.fpt" )
nSize := FSeek( nHandle, 0, FS_END )
FSeek( nHandle, -nSize, FS_RELATIVE )
cAllMemos := SPACE( nSize )
nRead := FRead( nHandle, @cAllMemos, nSize )
FCLOSE( nHandle )
? cAllMemos
RETURN NIL

cAllMemos contains in a single fRead all fpt file.

For instance I search string "MARCO" in cAllMemos string.
Obviously I know structure of MEMO2.DBF

The question is: is it possible to get the number of record and the
name of memo field that corresponds to this search?

what are the rules for storing contents of memo fields in the file
fpt?
Does exist some any documentation?


@Harbour
FlexFile3

*In this first memo field I write "MARCO"
¯ In this I write
"BOSCHI" ¯

Marco Boschi

unread,
Aug 9, 2010, 5:46:57 AM8/9/10
to

Marco Boschi

unread,
Aug 9, 2010, 5:48:46 AM8/9/10
to

Ella

unread,
Aug 9, 2010, 6:48:37 AM8/9/10
to
Marco,

On 9 aug., 12:48, Marco Boschi <i...@marcoboschi.it> wrote:
> #include "FileIO.ch"
>
> FUNCTION MAIN()
>
> LOCAL cAllMemos
>
>   // open and read all dbf file into cStringa variable
>   nHandle := FOPEN( "memo2.fpt" )
>   nSize := FSeek( nHandle, 0, FS_END )
>   FSeek( nHandle, -nSize, FS_RELATIVE )
>   cAllMemos := SPACE( nSize )
>   nRead := FRead( nHandle, @cAllMemos, nSize )
>   FCLOSE( nHandle )
>   ? cAllMemos
> RETURN NIL
>
> cAllMemos contains in a single fRead all fpt file.
>
> For instance I search string "MARCO" in cAllMemos string.
> Obviously I know structure of MEMO2.DBF
>
> The question is: is it possible to get the number of record and the
> name of memo field that corresponds to this search?

No

>
> what are the rules for storing contents of memo fields in the file
> fpt?
> Does exist some any documentation?

The DBF file's memo field contains a POINTER to the FPT file's zone,
which contains the proper data stream.

Here is a description og FPT file structure
http://msdn.microsoft.com/en-us/library/8599s21w(VS.80).aspx

Note: reading the FPT file as low-level file you can't even find out,
that the "parent" record of a piece of data is deleted or not ( FPT
files are cleaned up only when you do PACK ).

Ella

dlzc

unread,
Aug 9, 2010, 10:21:51 AM8/9/10
to
Dear Marco Boschi:

On Aug 9, 2:46 am, Marco Boschi <i...@marcoboschi.it> wrote:
...


> cAllMemos contains in a single fRead all fpt file.

OK, so you lose any easy hint of the "record location" within the memo
file when you do this.

> For instance I search string "MARCO" in
> cAllMemos string.
> Obviously I know structure of MEMO2.DBF
>
> The question is: is it possible to get the number of
> record and the name of memo field that corresponds
> to this search?

If you can infer what record it was in the memo file, then if you can
create a lookup table
of field names and record numbers (of the DBF), you can do a reverse
lookup. There is nothing in the fpt file structure itself that will
assist you in doing what you intend to do. And I'm not sure you can
get to the underlying value of the "memo field pointer"... without
making "temporary" changes to the DBF file header, turning the memo
fields into long integer fields (or something bizarre)

> what are the rules for storing contents of memo
> fields in the file fpt?
> Does exist some any documentation?

Some:
http://msdn.microsoft.com/en-us/library/8599s21w(VS.80).aspx

David A. Smith

Marco Boschi

unread,
Aug 9, 2010, 11:10:19 AM8/9/10
to
> Note: reading the FPT file as low-level file you can't even find out,
> that the "parent" record of a piece of data is deleted or not ( FPT
> files are cleaned up only when you do PACK ).

For me is not a problem to open dbf file to with USE at the same time.
Every record returned from search are also checked for deleted() or
not.
I

dlzc

unread,
Aug 9, 2010, 12:18:41 PM8/9/10
to
I have no idea how my post got recorded by Google.Groups ahead of
Ella's response...

> Dear Marco Boschi:
>
> On Aug 9, 2:46 am, Marco Boschi <i...@marcoboschi.it> wrote:
> ...
>
> > cAllMemos contains in a single fRead all fpt file.
>
> OK, so you lose any easy hint of the "record location"
> within the memo file when you do this.
>
> > For instance I search string "MARCO" in
> > cAllMemos string.
> > Obviously I know structure of MEMO2.DBF
>
> > The question is: is it possible to get the number of
> > record and the name of memo field that corresponds
> > to this search?
>
> If you can infer what record it was in the memo file,
> then if you can create a lookup table of field names
> and record numbers (of the DBF), you can do a
> reverse lookup.

Here is what you could do:
Open the original DBF.
Note all the field names that are memo fields.
Create a new database with the following structure:
RecrdNo
FldName
FldPtr
Create a record for each field that has a non-zero return value for
DbFieldInfo( DBS_BLOB_OFFSET, <nFieldPos> )
(assuming DBSTRUCT.CH is #included)
... as you scan through the original file.
Index on FldPtr
Do your merge-and-find, then softseek for the offset and you'll have
your record number and field name.

David A. Smith

Marco Boschi

unread,
Aug 9, 2010, 1:42:24 PM8/9/10
to
David,
I'm studying a fast search in a dbf table using low level function
likes Fopen, Fread, AT(.
I have noted that is dramatically faster than with traditional
commands and functions.
Obviously I'm talking about free searches on all fields.
I'm testing this function, you find source code below:

This function has two known limits to myself ( and probably many
others )

first limit: It works with string and not with words, in example
"Tom" .AND. "Street" and not " Tom " .AND. " Street "
second limit: It works only in table without memo fields.

I have to open and search in FPT table and get record number where
searched string is present ( is not important to obtain field name,
just know the record number.
Thanks for your attention


// parameters: dbf file to open and string to search with .AND. clause
( not words but strings! )
FUNCTION MAIN()

LOCAL aRecord := {}
LOCAL i
LOCAL cRecords := ""
LOCAL nRecord

aRecord := at_search( "customer", "Tom", "Street" )

FOR i := 1 TO LEN( aRecord )
cRecords := cRecords + " " + ALLTRIM( STR(aRecord[i]) )
NEXT i
? cRecords

USE customer
INDEX ON recno() TAG COD_CLI CUSTOM TO cust_rec
FOR EACH nRecord In aRecord
GOTO nRecord
OrdKeyAdd()
NEXT
// open browse to monitor
GO TOP
browse()

RETURN NIL

FUNCTION AT_SEARCH( cFile , cString1 , cString2, cString3, cString4 )

LOCAL iW1, iW2
LOCAL cStringa
LOCAL cIndRec := cFile + "_rec"

LOCAL nHandle
LOCAL nSize
LOCAL nRead
LOCAL nPosRec
LOCAL nHead, nRecSize

LOCAL nPosStart := 0
LOCAL nPosRecord := 0
LOCAL aPosRec1 := {}
LOCAL aPosRec2 := {}
LOCAL aString := {}
LOCAL nAndOr := 1
LOCAL aRecord := {}
LOCAL cTrova := ""
LOCAL nFound
LOCAL cRecord
LOCAL nPos2
LOCAL nIni := SECONDS()
LOCAL lDeleted

SET DELETED OFF
SET EXCLUSIVE OFF

// load an array with strings to search
IF cString1 <> NIL ; AADD( aString , UPPER( cString1 ) ) ;
ENDIF
IF cString2 <> NIL ; AADD( aString , UPPER( cString2 ) ) ;
ENDIF
IF cString3 <> NIL ; AADD( aString , UPPER( cString3 ) ) ;
ENDIF
IF cString4 <> NIL ; AADD( aString , UPPER( cString4 ) ) ;
ENDIF


// open and read all dbf file into cStringa variable

nHandle := FOPEN( cFile + ".dbf" )


nSize := FSeek( nHandle, 0, FS_END )
FSeek( nHandle, -nSize, FS_RELATIVE )

cStringa := SPACE( nSize )
nRead := FRead( nHandle, @cStringa, nSize )
FCLOSE( nHandle )
nIni := SECONDS()
cStringa := UPPER( cStringa )
? seconds() - nIni

// open with use commands to obtain header and recsize
USE &cFile
nHead := header()
nRecSize := recsize()
USE
nPosRec := 1
nFound := 0
iW1 := 1
iW2 := 1
nPosStart := 1

// enter in a loop to begin search operations
DO WHILE .T.

// search counter
nFound := 0

// aPosrec1 contain in position 1 the absolute position in
cStringa and in position
// 2 the calculated record
aPosRec1 := ATREC( aString[ 1 ] , cStringa , nPosStart, nHead,
nRecSize )

IF aPosRec1[ 1 ] > 0 // if the first string to search is
founded...

// if a * is present record is deleted
lDeleted := IIF(SUBSTR( cStringa , nHead + nRecSize *
( aPosrec1[ 2 ] -1) +1 , 1 ) = "*", .T., .F. )
IF .NOT. lDeleted
// start position for next search is the beginning of
record
nPosStart := aPosRec1[1] + 1

// IF there are other strings to search
IF LEN( aString ) > 1

// first string has been founded
nFound ++

// create a string containing only the actual record
nPosRecord := nHead + nRecSize * ( aPosrec1[ 2 ] - 1 )
+ 2
cRecord := SUBSTR( cStringa , nPosRecord ,
nRecSize )

// pointer for second string to search
iW2 := 2
DO WHILE .T.

// I search the second string only in the record
string (more little)
nPos2 := AT( aString[ iW2 ] , cRecord )

IF nPos2 > 0
// second string is founded
nFound ++
ELSE
// if not found exit from loop
EXIT
ENDIF

// if there are other strings to search increment
pointer of 1
IF iW2 < LEN( aString )
iW2 ++
ELSE
// otherwise exit
EXIT
ENDIF

ENDDO

// at the exit of loop IF all strings are founded I add
record number to aRecord Array
IF nFound = LEN( aString )
AADD( aRecord , aPosRec1[2] )
ENDIF
nPosStart ++

ELSE // there is only one string to search

AADD( aRecord , aPosRec1[2] )
ENDIF
ELSE

nPosStart := nPosStart + nHead + nRecSize

ENDIF
ELSE
EXIT
ENDIF
ENDDO

? SECONDS() - nIni

RETURN aRecord

FUNCTION ATREC( cTesto , cStringa , nStart, nHead, nRecSize )
LOCAL nPos := 0
LOCAL nRecord := 0
nPos := AT( cTesto , cStringa , nStart )

IF nPos > 0
nRecord := INT( ( nPos - nHead ) / nRecSize ) + 1
ENDIF
RETURN { nPos, nRecord }

FUNCTION DbfSize()
RETURN ( (RecSize() * LastRec()) + Header() + 1 )


INIT PROCEDURE RddInit
REQUEST DBFFPT
REQUEST DBFCDX
rddSetDefault( "DBFCDX" )
RETURN


dlzc

unread,
Aug 9, 2010, 3:01:17 PM8/9/10
to
Dear Marco Boschi:

On Aug 9, 10:42 am, Marco Boschi <i...@marcoboschi.it> wrote:
...

> I have to open and search in FPT table and get record
> number where searched string is present ( is not
> important to obtain field name, just know the record
> number. Thanks for your attention

Yes, and I described how you might do that. You did originally ask
which field the memo was stored in. Doesn't matter to me if you are
no longer interested in it.

I also find that
DbRecordInfo( DBRI_RAWDATA, [<nRecord>] )
(assuming DBINFO.CH is #included) will return the entire contents of a
record, including the contents of all numeric fields as text, and all
memo fields as text, in a single string.

I think you will find it easier to code your search, especially with
two or more search terms, if you avoid the low level file IO.

David A. Smith

Message has been deleted
0 new messages