Формат 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, если не получается с юникодом.