Home Joe Curran. Software Guy.

DBF to CSV

Here's a sample Visual Objects function to take a DBF file and output it to a CSV that can then be imported into a SQLite table.

FUNCTION DBF2CSV(cCSVFile AS STRING, cDBFFile AS STRING) AS VOID STRICT
// cCSVFile is the name of the output file; cDBFFile is the name of the DBF
LOCAL phandle AS PTR
LOCAL oOutput AS DBServer
LOCAL aResAry AS ARRAY
LOCAL nLen AS DWORD
LOCAL nTemCnt AS DWORD
LOCAL cString AS STRING
LOCAL cVar AS STRING
LOCAL cSeparator AS STRING
LOCAL CRLF AS STRING

CRLF := CHR( 13 ) + CHR(10) // line terminator

cSeparator := "|" // SQLite uses pipe characters as CSV separators

oOutput := DbServer{ cDBFFile }

// make an array of the dbf structure
aResAry := oOutput:DbStruct

// initialize the output CSV file
phandle := FCreate( cCSVFile, 0)

nLen := ALen( aResAry )

oOutput:GoTop()
WHILE !oOutput:EOF

cString := Space(0)
FOR nTemCnt :=1 UPTO nLen

// loop the file structure array; one element for each field

DO CASE
CASE aResAry[nTemCnt, DBS_TYPE] = "C" // if it's a character field
/*
// THIS IS IMPORTANT. Most tables will require a method for going to a specific record.
Difficult to do that in SQL without a unique identifier (something like a guid) for
each record. Here is where we check. If the field is FQ (our chosen name for the
unique identifier field), then we check to ensure it contains a unique identifier.

IF oOutput:FieldName( nTemCnt ) = "FQ" .AND. Empty( oOutput:FIELDGET( nTemCnt ) )
oOutput:XReplQ()
ENDIF
*/
// here we strip characters that will get in the way of the import

cVar := Trim( StrTran( oOutput:FIELDGET( nTemCnt ), ["]) ) // no quotes
cVar := StrTran( cVar, CRLF, "<CR>" ) // no returns
cVar := StrTran( cVar, CHR( 13 ) ) // found this in a notepad file
cVar := StrTran( cVar, CHR( 10 ) ) // found this in a notepad file
cVar := StrTran( cVar, CHR( 2 ) ) // found this in a notepad file

CASE aResAry[nTemCnt, DBS_TYPE ] = "N" // if it's a numeric field
IF oOutput:FIELDGET(nTemCnt) = 0
cVar := Space(0)
ELSE
cVar := LTrim(Str( oOutput:FIELDGET( nTemCnt ), aResAry[nTemCnt, 3], aResAry[nTemCnt, 4] ))
ENDIF

CASE aResAry[nTemCnt, DBS_TYPE ] = "D" // if it's a date, make it DToS()
cVar := DToS( oOutput:FIELDGET( nTemCnt ) )

CASE aResAry[nTemCnt, DBS_TYPE ] = "L" // if it's a logic field, make it Y or N
cVar := IIF( oOutput:FIELDGET( nTemCnt ) = TRUE, "Y", "N" )

OTHERWISE
cVar := Space(0)
ENDCASE
// remove any pipe characters that might be contained in the field
cVar := StrTran( cVar, cSeparator )

IF nTemCnt = 1
// if it's the first field in the record, create a new string
cString := cVar
ELSE
cString += cSeparator + cVar
ENDIF

NEXT

FWrite( phandle, cString + CRLF ) // write the string and terminate with CR/LF
oOutput:Skip( 1 )
ENDDO
oOutput:Close()
FClose(phandle)

RETURN