F9
Новичок
- Сообщения
- 71
- Репутация
- 2
Добрый день!
Столкнувшись с необходимостью работы в DBF-файлами, не обнаружил на данном форуме чего-либо полезного.
Поэтому, вооружившись гуглом нашел некоторые источники, и как результат привожу примеры своего кода, который возможно будет полезен кому-либо.
Во-первых, очень полезный ресурс https://www.connectionstrings.com/, будет полезен всем кто пишет свои внешние обработчики БД.
Во-вторых, ресурс http://www.script-coding.com/ADO.html также подарит много методов и свойств для работы с полученными данными.
Итак, извлечение данных из DBF-файла (занесение в массив):
Объект Recordset состоит из записей и полей. Не все свойства объекта поддерживаются всеми провайдерами. Например пресловутое RecordCount будет априори "-1", т.к. не поддерживается этим провайдером.
А вот с UPDATE я сначала прилип, так как логика UPDATE провайдера Microsoft dBASE Driver отличается от MySQL или FireBird.
К примеру, данные команды
Не дадут никакого эффекта, хотя и ошибок выполнения не будет. Почему-то даже $rs.Update или $rs.Commit или $rs.CommitTrans не дают эффекта сохранения данных рекордсета в файл.
Правильно будет использовать
8)
UPD:
Есть еще один способ извлечения данных и записи (частично) - через UDF
DBF.7z - во вложении
Вполне рабочий инструмент, отстутствуют только функции Update, insert и тп
:whistle: :whistle:
UPD2:
Еще один пример чтения DBF-файла из сети:
Столкнувшись с необходимостью работы в DBF-файлами, не обнаружил на данном форуме чего-либо полезного.
Поэтому, вооружившись гуглом нашел некоторые источники, и как результат привожу примеры своего кода, который возможно будет полезен кому-либо.
Во-первых, очень полезный ресурс https://www.connectionstrings.com/, будет полезен всем кто пишет свои внешние обработчики БД.
Во-вторых, ресурс http://www.script-coding.com/ADO.html также подарит много методов и свойств для работы с полученными данными.
Итак, извлечение данных из DBF-файла (занесение в массив):
Код:
#include <Array.au3>
Dim $Arr[0][2]
Global $Connect = ObjCreate ("ADODB.Connection")
$Connect.Open("Driver={Microsoft dBASE Driver (*.dbf)};DriverID=277;Dbq=C:Temp\DBF\") ;Dbq - путь к папке, где лежат dbf-файлы. Сам файл указывать не нужно
If $Connect.State = 0 Then
MsgBox(0,"","Невозможно подключиться к БД",5)
Exit
EndIf
$rs = ObjCreate("ADODB.recordset") ; создание объекта RecordSet
$rs.open ('"Select * from test.dbf"', $Connect)
With $rs
While Not .EOF
_ArrayAdd($Arr, $rs.Fields(1).Value &"|"& $rs.Fields(2).Value)
.MoveNext
WEnd
EndWith
_ArrayDisplay($Arr)
$rs.Close
Объект Recordset состоит из записей и полей. Не все свойства объекта поддерживаются всеми провайдерами. Например пресловутое RecordCount будет априори "-1", т.к. не поддерживается этим провайдером.
А вот с UPDATE я сначала прилип, так как логика UPDATE провайдера Microsoft dBASE Driver отличается от MySQL или FireBird.
К примеру, данные команды
Код:
$rs.open("UPDATE TEST.DBF FILE SET FILE.Field1 = '100500' WHERE FILE.Field2 = '1'")
$rs.Execute("UPDATE TEST.DBF FILE SET FILE.Field1 = '100500' WHERE FILE.Field2 = '1'")
Не дадут никакого эффекта, хотя и ошибок выполнения не будет. Почему-то даже $rs.Update или $rs.Commit или $rs.CommitTrans не дают эффекта сохранения данных рекордсета в файл.
Правильно будет использовать
Код:
;~ .... все из предыдущего примера....
$sqlCMD = ObjCreate("ADODB.Command") ; Создание объекта Command
$sqlCMD.ActiveConnection = $Connect
$sqlCMD.CommandText = "UPDATE TEST.DBF FILE SET FILE.Field1 = '100500' WHERE FILE.Field2 = '1'"
$sqlCMD.Execute
8)
UPD:
Есть еще один способ извлечения данных и записи (частично) - через UDF
DBF.7z - во вложении
Вполне рабочий инструмент, отстутствуют только функции Update, insert и тп
:whistle: :whistle:
UPD2:
Еще один пример чтения DBF-файла из сети:
Код:
#include-once
;===============================================================================
;
; Description: Directly read DBF database file to array
; Parameter(s): $sFileName - name of DBF file
; $nFlags
; 1 - convert from OEM to ANSI
; 2 - strip leading and trailing witespaces
; Requirement(s): Autoit 3.2.9.0 +
; Return Value(s): On Success - 2D array, first row - names of fields
; On Failure - no decent way to check errors
; Author(s): Dmitry Yudin (Lazycat)
; Version: 0.3
; Date: 14.12.2009
; Note(s): Many DBF functions and flags are not read - just because
; I wasn't need it
;
;===============================================================================
_ArrayDisplay(_FileReadDBF(@ScriptDir & "\File.dbf",2))
Func _FileReadDBF($sFileName, $nFlags = 0)
Local $hFile = FileOpen($sFileName, 16)
Local $pReadBuffer = DllStructCreate("byte[32]") ; Header size
DllStructSetData($pReadBuffer, 1, FileRead($hFile, 32))
$pDBFHeader = DllStructCreate("byte;byte;byte;byte;int;short;short;byte[20]" , DllStructGetPtr($pReadBuffer)) ; Header struct
$nRecords = DllStructGetData($pDBFHeader, 5) ; Get number of records
$nDataPos = DllStructGetData($pDBFHeader, 6) ; Get data start position
$nRecordSize = DllStructGetData($pDBFHeader, 7) ; Get record size (included deleted flag)
$nFields = Floor($nDataPos / 32) - 1
$nDataGap = $nDataPos - ($nFields + 1) * 32
Local $aData[$nRecords+1][$nFields]
Local $sRecordStruct = "byte;" ; Struct string, based on fields size and type, first byte - deleted mark
For $i=0 To $nFields - 1
DllStructSetData($pReadBuffer, 1, FileRead($hFile, 32))
$pField = DllStructCreate("char[11];byte;int;byte;byte[15]" , DllStructGetPtr($pReadBuffer)) ; Field structure
$aData[0][$i] = DllStructGetData($pField, 1) ; Name of field
; Create struct based on field size and type (now unfinished, treat all types as string)
Switch DllStructGetData($pField, 2)
Case Asc("C") or Asc("D") ;or Else
$sRecordStruct &= "char[" & DllStructGetData($pField, 4) & "];"
EndSwitch
Next
$sRecordStruct = StringTrimRight($sRecordStruct, 1) ; Trim last ";"
FileRead($hFile, $nDataGap) ; Skip ending marker, it's size may vary
$pReadBuffer = DllStructCreate("byte["&$nRecordSize&"]") ; New buffer, now based on record size
For $i = 1 To $nRecords
DllStructSetData($pReadBuffer, 1, FileRead($hFile, DllStructGetSize($pReadBuffer)))
$pRecord = DllStructCreate($sRecordStruct , DllStructGetPtr($pReadBuffer))
For $j = 0 To $nFields - 1
$aData[$i][$j] = DllStructGetData($pRecord, $j+2)
If BitAND($nFlags, 1) Then $aData[$i][$j] = _Ascii2Ansi($aData[$i][$j])
If BitAND($nFlags, 2) Then $aData[$i][$j] = StringStripWS($aData[$i][$j], 3)
Next
Next
FileClose($hFile)
Return $aData
EndFunc
; Helper function, convert OEM text to ANSI
Func _Ascii2Ansi($sText)
Local $src = DllStructCreate("char[" & StringLen($sText) + 1 & "]")
Local $dst = DllStructCreate("char[" & StringLen($sText) + 1 & "]")
DllStructSetData($src, 1, $sText)
DllCall("user32.dll", "int", "OemToCharA", "ptr", DllStructGetPtr($src), "ptr", DllStructGetPtr($dst))
Return DllStructGetData($dst, 1)
EndFunc