Автор Тема: [ADODB] Работа с DBF файлами  (Прочитано 690 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн F9 [?]

  • Новичок
  • *
  • Сообщений: 71
  • Репутация: 1
    • Награды
  • Версия AutoIt: 3.3.14.0
[ADODB] Работа с DBF файлами
« Создано: Сентябрь 14, 2017, 10:58:47 »
Добрый день!

Столкнувшись с необходимостью работы в DBF-файлами, не обнаружил на данном форуме чего-либо полезного.
Поэтому, вооружившись гуглом нашел некоторые источники, и как результат привожу примеры своего кода, который возможно будет полезен кому-либо.

Во-первых, очень полезный ресурс https://www.connectionstrings.com/, будет полезен всем кто пишет свои внешние  обработчики БД.

Во-вторых, ресурс http://www.script-coding.com/ADO.html также подарит много методов и свойств для работы с полученными данными.

Итак, извлечение данных из DBF-файла (занесение в массив):

Код: AutoIt [Выделить]
#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.
К примеру, данные команды
Код: AutoIt [Выделить]
$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 не дают эффекта сохранения данных рекордсета в файл.
Правильно будет использовать
Код: AutoIt [Выделить]
;~ .... все из предыдущего примера....
$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-файла из сети:
Код: AutoIt [Выделить]
#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
 



Внимание: Для просмотра прикреплённых файлов необходимо Войти или Зарегистрироваться
« Последнее редактирование: Сентябрь 14, 2017, 11:04:09 от F9 »

Русское сообщество AutoIt

[ADODB] Работа с DBF файлами
« Отправлен: Сентябрь 14, 2017, 10:58:47 »

Онлайн ra4o [?]

  • Скриптер
  • ****
  • Сообщений: 670
  • Репутация: 113
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.14.0
Re: [ADODB] Работа с DBF файлами
« Ответ #1, Отправлен: Сентябрь 14, 2017, 21:05:44 »
Интересное решение, но лично для себя нашел интересную библиотеку в комплекте с dll - широкий набор функций, просто и удобно в работе. Архив прилагаю, пробуйте.


Внимание: Для просмотра прикреплённых файлов необходимо Войти или Зарегистрироваться

Онлайн Alofa [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 1205
  • Репутация: 171
  • Пол: Мужской
  • Windows7 (x64)
    • Награды
  • Версия AutoIt: 3.3.12.0
Re: [ADODB] Работа с DBF файлами
« Ответ #2, Отправлен: Сентябрь 14, 2017, 22:52:36 »
OffTopicra4o
(нажмите для показа/скрытия)

Оффлайн F9 [?]

  • Новичок
  • *
  • Сообщений: 71

  • Автор темы
  • Репутация: 1
    • Награды
  • Версия AutoIt: 3.3.14.0
Re: [ADODB] Работа с DBF файлами
« Ответ #3, Отправлен: Сентябрь 15, 2017, 05:45:07 »
Интересное решение, но лично для себя нашел интересную библиотеку в комплекте с dll - широкий набор функций, просто и удобно в работе. Архив прилагаю, пробуйте.
Увы, с ней нельзя выполнять стандартные запросы.




Добавлено: Сентябрь 15, 2017, 05:48:09
Столкнулся с еще одной проблемой : не выполняется INSERT.
Синтаксис самого запроса корректен, проверял на таблицах через VFP 9.0

Код: AutoIt [Выделить]
    Global $Connect = ObjCreate ("ADODB.Connection")
    $Connect.Open("Driver={Microsoft dBASE Driver (*.dbf)};DriverID=277;Dbq="& @ScriptDir& "\DBF\")
    $Connect.Mode=3

$sqlCMD = ObjCreate("ADODB.Command")
$sqlCMD.ActiveConnection = $Connect
$sqlCMD.CommandType = "adCmdTable"
$sqlCMD.CommandText = "insert INTO '15_09.DBF' (Ndok, Typedoc) VALUES ('7','7')"  ;не происходит никакого INSERT данных
;~ $sqlCMD.CommandText = "UPDATE 15_09.DBF FILE SET FILE.Typedoc = '12' WHERE FILE.ndok = '1'" ; UPDATE при этом совершенно прекрасно работает.
;~ $Connect.Execute("insert INTO '15_09.DBF' (DateReg, Ndok, Typedoc) VALUES ({^2016-01-02},'5','1')")  ;так тоже не выполняется

$sqlCMD.Execute
 


Русское сообщество AutoIt

Re: [ADODB] Работа с DBF файлами
« Ответ #3 Отправлен: Сентябрь 15, 2017, 05:45:07 »

 

Похожие темы

  Тема / Автор Ответов Последний ответ
7 Ответов
4805 Просмотров
Последний ответ Ноябрь 17, 2009, 07:55:04
от SyDr
17 Ответов
6605 Просмотров
Последний ответ Июнь 03, 2010, 13:37:48
от ynbIpb
8 Ответов
6571 Просмотров
Последний ответ Апрель 04, 2011, 20:56:54
от Sniper
21 Ответов
11175 Просмотров
Последний ответ Октябрь 15, 2016, 10:43:31
от ra4o
1 Ответов
2738 Просмотров
Последний ответ Февраль 13, 2012, 12:59:40
от madmasles
1 Ответов
1680 Просмотров
Последний ответ Сентябрь 19, 2013, 16:48:27
от madmasles
0 Ответов
1504 Просмотров
Последний ответ Январь 12, 2014, 04:27:07
от Astel064
1 Ответов
731 Просмотров
Последний ответ Июль 12, 2016, 12:23:26
от pvnn
2 Ответов
563 Просмотров
Последний ответ Январь 30, 2017, 09:44:15
от ra4o
7 Ответов
345 Просмотров
Последний ответ Август 12, 2017, 17:27:27
от Garrett