Aquí les dejo una función que he estado haciendo estos días (tenía tiempo).
La finalidad es la búsqueda de un valor dentro de una DBF mediante la función At().
Creo que sólo será útil para ficheros enormes; para los más pequeños las funciones de Harbour ya nos valen.
Agradecería que alguién que tenga algún fichero DBF enorme la pruebe y nos diga si és más rápido que con el comando LOCATE.
Yo no puedo hacerlo, no dispongo de ficheros enormes (ni tampoco espacio en el disco, je, je).
Un Saludo y gracias
Carlos G.
- Code: Select all Expand view
#include "fivewin.ch"
#include "Dbstruct.ch"
#include "DbInfo.ch"
/* Función para buscar en una DBF (en su orden NATURAL) un valor contenido
en un campo determinado.
Simula el comando LOCATE y CONTINUE, pero realizando un AT().
Devuelve el Recno() ó '0' según encuentre o no el valor a buscar.
Se asume que la DBF está abierta y se recibe su Alias().
Su uso es:
nAtInDbf( cAliasDBF, "APELLIDO", "GARCIA", .F. )
para continuar la búsqueda con los mismos parámetros:
nAtInDbf( cAliasDBF, , , .T. )
Para que nos entendamos, la primera vez vendría a ser un LOCATE, y la segunda
vez vendría a ser un CONTINUE.
--------------------------------------------------------------------------------- */
FUNCTION nAtInDbf( cAliasDBF, cFieldDBF, cString, lContinue )
STATIC cMemoDbf := "", ;
nBytesToField := 0, ;
nBytesEndField := 0, ;
nOffset := 0, ;
cSearch := "", ;
cfield := "", ;
nRegLocate_1 := 0
Local aEstruct := {}
Local nPos := 0
DEFAULT lContinue := .F.
/*
Traza( 1, cAliasDbf )
Traza( 1, ( cAliasDbf )->(DbInfo( DBI_FULLPATH )) )
Traza( 1, cFieldDbf )
Traza( 1, cString )
Traza( 1, lContinue )
*/
If .not. lContinue
If Len( cString ) < 1
MsgInfo("Not Data to Search.", "Search Error." )
Return 0
Endif
cMemoDbf := MemoRead( ( cAliasDbf )->(DbInfo( DBI_FULLPATH )) )
nOffset := 0
cSearch := cString
cField := Upper( cfieldDBF )
nRegLocate_1 := 0
nBytesToField := 0
nBytesEndField := 0
aEstruct := ( cAliasDBF )->(DBSTRUCT())
AScan( aEstruct, { |aCampo| If( aCampo[ DBS_NAME ] == cField, ;
(nBytesEndField := nBytesToField + aCampo[ DBS_LEN ] + aCampo[ DBS_DEC ], .T.), ;
(nBytesToField := nBytesToField + aCampo[ DBS_LEN ] + aCampo[ DBS_DEC ], .F. ) ;
) ;
} ;
)
If nBytesEndField = 0
MsgInfo("Field not found.", "Search Error." )
Return 0
Endif
EndIf
nPos := 0
While nPos <= ( ( cAliasDBF )->(Header()) + (nRegLocate_1 * ( cAliasDBF )->(RecSize()) ) + nBytesToField) .or. ;
nPos > ( ( cAliasDBF )->(Header()) + (nRegLocate_1 * ( cAliasDBF )->(RecSize()) ) + nBytesEndField)
nPos := AT( cSearch, SubStr(cMemoDbf, nOffset + 1) )
If nPos = 0
nRegLocate_1 = -1
Exit
EndIf
nOffset := nPos := nPos + nOffSet
nRegLocate_1 := INT( ( nPos - ( cAliasDBF )->(Header()) ) / ( cAliasDBF )->(RecSize()) ) // Registro anterior al localizado¿?
If (( nPos - ( cAliasDBF )->(Header()) ) % ( cAliasDBF )->(RecSize())) = 0
nRegLocate_1 = nRegLocate_1 - 1 // Registro anterior al localizado.
EndIf
End
Return nRegLocate_1 + 1
//------------------------------------------------------------------