Konvertierung *.dbf zu *.xls oder *.txt

    • Offizieller Beitrag

    Hi,
    kennt jemand einen eleganten Weg, eine dbf-Datei in Excel- oder sogar Textformat zu konvertieren?
    Aus unserer Firmensoftware kann ich Ergebnistabellen ausschließlich im dbf-Format erhalten. Bisher helfe ich mir so, dass ich diese in Excel öffne und dann als xls-Datei abspeichere. Die weitere Verarbeitung läuft dann über die Excel-UDF mit AutoIt.
    Wäre nicht schlecht, wenn ich die dbf direkt in Text wandeln könnte - oder zumindest automatisiert in xls.
    Bin für jede Anregung dankbar.

    Habe mal eine Muster-dbf angehängt, da das ja ein frei interpretiertes Format ist.

  • Das kannst du schon machen, am besten mit _WinAPI_ReadFile und structures ;)
    //Edit: war falschens dbase format...
    Das sollte stimmen:

    Spoiler anzeigen

    http://www.sac.sk/files.php?d=12&l=D --> ftp://ftp.sac.sk/pub/sac/text/dbf_eng.zip

    2 Mal editiert, zuletzt von progandy (9. Dezember 2008 um 21:20)

    • Offizieller Beitrag

    Hi Xeno,
    ja Dank progandy's super Hilfe konnte ich das fertigstellen und habe es seitdem ununterbrochen in der Firma im Einsatz. :thumbup:
    Ist jetzt speziell auf meine Problemstellung zugeschnitten, aber wenn du es dir ansehen willst, melde dich.

    Edit:
    Ich hab dir mal die betreffenden Funktionen aus meinem Skript rausgesucht. Die Zeilen, die sich auf den Rest des Skripts (GUI etc.) beziehen einfach ignorieren. ;)

    Spoiler anzeigen
    [autoit]

    Global Const $tagField = "char name[11];" & _ ; 0-10 | 11 bytes | field name
    "char type;" & _ ; 11 | 1 byte | field type in ASCII
    "uint memadress;" & _ ; 12-15 | 32 bit number | field data address
    "byte len;" & _ ; 16 | 1 byte | field length
    "byte deccount;" & _ ; 17 | 1 byte | field decimal count
    "byte reserved[14];" ; 18-31 | 14 bytes | reserved bytes
    Global Const $tagFileHeader = "byte ver;" & _ ; 0 | 1 byte | dBASE III version number
    "byte date[3];" & _ ; 1-3 | 3 bytes | date of last update
    "uint reccount;" & _ ; 4-7 | 32 bit number | number of records in data file
    "ushort headerlength;" & _ ; 8-9 | 16 bit number | length of header structure
    "ushort reclength;" & _ ; 10-11 | 16 bit number | length of the record
    "byte reserved[20];" ; 12-31 | 20 bytes | reserved bytes
    ;~ $tagField & _ ; 32-n | 32 bytes each | field descriptor array
    ;~ "byte terminate;" ; n+1 | 1 byte | 0DH as the field terminator
    Global $Header = DllStructCreate($tagFileHeader)

    [/autoit] [autoit][/autoit] [autoit]

    Func _CreateRecordStruct(ByRef $databaseFieldInfos)
    Local $sText = "char deleted;"
    For $i = 1 To UBound($databaseFieldInfos)
    $sText &= "char field" & $i & "[" & $databaseFieldInfos[$i - 1][3] & "];"
    Next
    Return DllStructCreate($sText)
    EndFunc ;==>_CreateRecordStruct

    [/autoit] [autoit][/autoit] [autoit]

    Func bLoadClick()
    $Path = FileOpenDialog('Rechnungsdatei wählen', $load, 'DBF(*.dbf)')
    If @error Then Return MsgBox(0, 'Fehler', 'Keine Datei ausgewählt')
    GUICtrlSetState($bLoad, $GUI_DISABLE)
    $DBFFile = _WinAPI_CreateFile($Path, 2, 2, 2)
    Local $ReadChars
    If _WinAPI_ReadFile($DBFFile, DllStructGetPtr($Header), DllStructGetSize($Header), $ReadChars) Then
    If DllStructGetData($Header, "ver") <> 3 Then ; Version muss
    MsgBox(16, 'Error', "No supportet dbase format (only dbase 3 without .DBT-files)")
    _WinAPI_CloseHandle($DBFFile)
    Exit
    EndIf
    ; $tagField erstellen
    Local $FieldDescriptor = DllStructCreate($tagField)
    ;, Infos aus Header auslesen
    Local $HeaderLength = DllStructGetData($Header, "headerlength")
    Local $FieldsCount = Floor(($HeaderLength - DllStructGetSize($Header) - 1) / DllStructGetSize($FieldDescriptor))
    Local $RecordLength = DllStructGetData($Header, "reclength")
    Local $RecordsCount = DllStructGetData($Header, "reccount")
    ; Zahl der Felder: (Headergröße - Dateiheadergröße - terminator-byte) / Feldbeschreibungs-größe
    If $FieldsCount = 0 Then
    MsgBox(16, '', "No fields")
    Else
    Global $DatabaseArray[$RecordsCount + 1][$FieldsCount]
    Global $databaseFieldInfos[$FieldsCount][5]
    For $i = 1 To $FieldsCount
    _WinAPI_ReadFile($DBFFile, DllStructGetPtr($FieldDescriptor), DllStructGetSize($FieldDescriptor), $ReadChars)
    $DatabaseArray[0][$i - 1] = DllStructGetData($FieldDescriptor, "name")
    For $s = 0 To 4
    $databaseFieldInfos[$i - 1][$s] = DllStructGetData($FieldDescriptor, $s + 1)
    Next
    Next
    Local $CHECKREAD = DllStructCreate("byte terminate")
    _WinAPI_ReadFile($DBFFile, DllStructGetPtr($CHECKREAD), 1, $ReadChars)
    If DllStructGetData($CHECKREAD, 1) == 0x0D Then
    $RecordStruct = _CreateRecordStruct($databaseFieldInfos)
    GUICtrlSetState($Progress1, $GUI_SHOW)
    GUICtrlSetData($lbMsg, 'Daten werden konvertiert')
    $iStep = 100/$RecordsCount
    For $i = 1 To $RecordsCount
    $iProgress += $iStep
    GUICtrlSetData($Progress1, $iProgress)
    _WinAPI_ReadFile($DBFFile, DllStructGetPtr($RecordStruct), DllStructGetSize($RecordStruct), $ReadChars)
    If $ReadChars = 0 Then
    ; keine Felder mehr (Fehler)
    ReDim $DatabaseArray[$i][$FieldsCount]
    ExitLoop
    EndIf
    For $j = 1 To $FieldsCount
    $DatabaseArray[$i][$j - 1] = DllStructGetData($RecordStruct, "field" & $j)
    #Region Datentypen konvertieren
    Switch $databaseFieldInfos[$j - 1][1]
    Case "C" ; characters: nothing
    If StringInStr($DatabaseArray[$i][$j - 1], "00:00:00", 1) Then
    $DatabaseArray[$i][$j - 1] = StringStripWS(StringRegExpReplace($DatabaseArray[$i][$j - 1], _
    "(\d\d)(\.)(\d\d)(\.)(\d{4})(\s00:00:00)", "$1$3$5"), 3)
    Else
    $DatabaseArray[$i][$j - 1] = OemToChar($DatabaseArray[$i][$j - 1])
    If StringLen($DatabaseArray[$i][$j - 1]) > 30 Then _
    $DatabaseArray[$i][$j - 1] = StringLeft($DatabaseArray[$i][$j - 1], 30)
    EndIf
    Case "N" ; numeric
    If StringInStr($DatabaseArray[$i][$j - 1], '.') Then
    $DatabaseArray[$i][$j - 1] = StringTrimRight(StringStripWS(StringReplace($DatabaseArray[$i][$j - 1], '.', ','), 1), 2)
    Else
    $DatabaseArray[$i][$j - 1] = Number($DatabaseArray[$i][$j - 1])
    EndIf
    Case "L"
    Switch $DatabaseArray[$i][$j - 1]
    Case "?"
    $DatabaseArray[$i][$j - 1] = "N/A"
    Case 'Y', 'y', 'T', 't'
    $DatabaseArray[$i][$j - 1] = True
    Case 'N', 'n', 'F', 'f'
    $DatabaseArray[$i][$j - 1] = False
    EndSwitch
    Case "D"
    $DatabaseArray[$i][$j - 1] = StringRegExpReplace($DatabaseArray[$i][$j - 1], "\A(\d{4})(\d\d)(\d\d)\Z", "$1/$2/$3")
    Case "M" ; not supportet
    EndSwitch
    #EndRegion Datentypen konvertieren
    Next
    Sleep(10)
    Next
    Else
    MsgBox(0, 'Error', "Wrong fielddescriptortable")
    EndIf
    EndIf
    _WinAPI_CloseHandle($DBFFile)
    EndIf
    ; Spalten infos hizugügen zu Feld-Info array
    ;~ ReDim $databaseFieldInfos[UBound($databaseFieldInfos)+1][5]
    ;~ $databaseFieldInfos[UBound($databaseFieldInfos)-1][0] = "[[ NAME ]]"
    ;~ $databaseFieldInfos[UBound($databaseFieldInfos)-1][1] = "[[ TYP ]]"
    ;~ $databaseFieldInfos[UBound($databaseFieldInfos)-1][2] = "[[ ADRESSE ??? ]]"
    ;~ $databaseFieldInfos[UBound($databaseFieldInfos)-1][3] = "[[ Byte-Länge ]]"
    ;~ $databaseFieldInfos[UBound($databaseFieldInfos)-1][4] = "[[ Dezimalstellen ]]"
    GUICtrlSetData($Progress1, 100)
    Sleep(1000)
    GUICtrlSetData($vonDat, $DatabaseArray[1][3])
    GUICtrlSetData($bisDat, $DatabaseArray[UBound($DatabaseArray)-1][3])
    GUICtrlSetData($lbMsg, 'Konvertierung abgeschlossen - Bereit zum Export')
    Sleep(500)
    GUICtrlSetData($Progress1, 0)
    GUICtrlSetState($bExport, $GUI_ENABLE)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ;===============================================================================
    ; Name: OemToChar
    ; Description: Wandelt einen ASCII- in einen ANSI-String
    ; Parameter(s): $szSrc = String der umgewandelt werden soll
    ; Requirement(s): keine
    ; Return Value(s): bei Erfolg: umgewandelter String
    ; bei Fehler: "" und @error = 1
    ; Author(s): bernd670
    ;===============================================================================
    Func OemToChar($szSrc)
    ;~ Private Declare Function OemToChar Lib "user32.dll" Alias "OemToCharA" (ByVal lpszSrc As String, ByVal lpszDst As String) As Long
    Local $placeholder
    For $i = 0 To StringLen($szSrc)
    $placeholder &= " "
    Next
    Local $lRetVal = DllCall("user32.dll", "long", "OemToChar", "str", $szSrc, "str",$placeholder)
    If IsArray($lRetVal) And $lRetVal[0] = 1 Then
    Return SetError(0,0,$lRetVal[2])
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Return SetError(1,0,"")
    EndFunc ;==>OemToChar

    [/autoit]