Работа с DBF в Питоне
Формат DBF, хоть и признан устаревшим, до сих пор широко используется в финансовых учреждениях. Он подходит для обмена табличными данными, такими, например, как отчеты и реестры платежей. Формат имеет простую логическую структуру, поэтому библиотеку для работы с ним можно написать самостоятельно. Классический DBF поддерживает основные типы данных — числа, строки, даты и булево. Благодаря этому дата, записанная в DBF, будет считата как дата, а не текстовая строка, которую будет необходимо парсить.
Для работы с файлами DBF в Питоне потребуется библиотека dbfpy. Это, кстати, не единственное решение, есть еще библиотеки pyDBF и dbf. Сам я работал только с первой из трех, функционал полность устраивает.
Приведу пару примеров: чтение и запись файла.
from dbfpy import dbf
# Открываем имеющийся файл.
db = dbf.Dbf("dbfile.dbf")
# Обход всех записей.
for rec in db:
print rec
# Извлечение записи по номеру.
rec = db[42]
# Значения полей извлекаются по их именам.
value = rec["VALUE"]
account = rec["ACCOUNT"]
date = rec["DATE"]
# Всегда закрывайте файл.
db.close()
Запись нового файла немного сложнее, так как потребуется указать схему данных. Фрагмент кода из реального проекта:
from dbfpy import dbf
# Определяем набор полей файла. C — строка, N — число, D — дата, L — булево.
# Для строк нужно указать длину, для чисел — количество разрядов целой и дробной частей.
SCHEMA = (
("PSU", "C", 64 ),
("TSO", "C", 64 ),
("PAYMENT", "N", 16, 0),
("SERVICE", "N", 8, 0),
("DATE", "D" ),
("MRO", "C", 64 ),
("TERMINAL", "N", 8, 0),
("ACCOUNT", "C", 16 ),
("SUMMARY", "N", 16, 2),
("OPERATOR", "N", 8, 0),
("SUPPLIER", "N", 8, 0),
("TIME", "C", 8 ),
("LAST_NAME", "C", 64 ),
("FIRST_NAME", "C", 64 ),
("MIDDLE_NAM", "C", 64 ),
)
db = dbf.Dbf("dbfile.dbf", new=True)
db.addField(*SCHEMA)
# Обходим в цикле данные, которые необходимо записать в DBF.
# В данном случае payments — объект QuerySet из Джанго.
# На каждом шаге цикла создается новая запись и заполняются ее поля.
for payment in payments:
rec = db.newRecord()
rec["ACCOUNT"] = payment.account
rec["FIRST_NAME"] = payment.first_name.encode("cp866")
rec["date"] = payment.date
# Заполняем остальные поля...
# Сохранение записи.
rec.store()
db.close()
Готово, файл создан.
Наверняка вы обратили внимание на кодирование поля
payment.first_name
. Это unocode-строка, и для того, чтобы записать
ее в файл, необходимо сперва преобразовать в обычную строку в какой-то
кодировке. Исторически сложилось так, что основной кодировкой для
этого формата является OEM, она же DOS, она же cp866
. Многие
программы, например, офисные Эксель и Акцесс работают с DBF-файлами
именно в этой кодировке. Чтобы созданные вами файлы читались в
сторонних программах, преобразовывайте перед записью строки с
кириллицей в cp866
.
Работать с DBF можно как с SQL-базой через драйвер ODBC. При этом именем таблицы является имя файла. Доступны все CRUD-операции на записями. Склеить два DBF-файла оператором JOIN, к сожалению, нельзя. Для работы с ODBC-источниками скачайте библиотеку pyodbc.
import pyodbc
# Строка, определяющая источник ODBC. DefaultDir — директория с DBF-файлом.
s = "Driver={Microsoft dBASE Driver (*.dbf)};DefaultDir=d:\\temp"
db = pyodbc.connect(s, autocommit=True)
cursor = db.cursor()
# Пример выборки.
cursor.execute('''
SELECT
value,
account,
date
FROM
dbfile
WHERE
processed = 'false'
''')
# Извлечение записи.
row = cursor.fetchone()
if row:
print row
# Закрываем курсор и ресурс.
cursor.close()
db.close()
Вставка, удаление и обновление записей реализуются аналогично согласно SQL-синтаксису:
cursor.execute('''
DELETE FROM
dbfile
WHERE
processed = 'false'
''')
cursor.execute('''
UPDATE
dbfile
SET
account = 'test',
value = 42
WHERE
id = 1
''')
Какой способ работы с DBF задействовать в проекте — решать вам. dbfpy не требует сторонних зависимостей, написана на чистом Питоне, может работать в сервисах типа App Engine, однако, не столь быстра, как pyodbc. Последняя, напротив, быстрее, но зависит от платформы и иногда глючит на Винде (у меня были проблемы с ошибками в DLL-библиотеках). Для небольших проектов рекомендую использовать dbfpy, в промышленных масштабах — pyodbc.
Комментарии из старого блога
04/08/14 Городецкий: привет! получаю invalid syntax
при from
dbfpy import dbf
. Подскажи пожалуйста, что не так?
04/09/14 Иван Гришаев: Точка в конце не нужна. Или какая-то из букв кириллическая. Трейс должен показывать стрелочкой, где косяк.
01/09/15 Ole: Отличный пост
09/02/15 Дамир Аманов: в pyodbc как работать с кириллицой? в windows
09/03/15 Иван Гришаев: Насколько помню, кодировать строки в cp2151, если не получается с юникодом.
Нашли ошибку? Выделите мышкой и нажмите Ctrl/⌘+Enter
Oleg Veres, 14th Aug 2018, link
Привет. Выдаёт такие ошибки:
Traceback (most recent call last): from dbfpy import dbf - это ругается на "from dbfpy import dbf"
File "C:\Users\......\AppData\Local\Programs\Python\Python37-32\lib\site-packages\dbfpy\dbf.py", line 280
print repr(_rec)
Ivan Grishaev, 14th Aug 2018, link , parent
Либа под второй питон, а вас третий.
Oleg Veres, 14th Aug 2018, link , parent
Спасибо.
Не можете подстазать что либо под третьего питона?
Ivan Grishaev, 14th Aug 2018, link , parent
Быстрый поиск ничего не дает. Либо писать под второй, либо портировать библиотеку. Мне кажется, второе будет несложно, либа маленькая.
mic, 25th Apr 2020, link
Красивая статья, кратко и ясно. Все работает, огромное спасибо!