Реінкарнація даних ii memo-поля

Починаючи з 513-го байта від початку файлу, розташовуються блоки даних. Значення поля може займати один або кілька блоків. Кожен блок, який є першим для запису, містить 8-байтний заголовок (4 байта сигнатура 0х00000001 і 4 байта - довжина поля), після якого йдуть власне дані.

Для забезпечення зв'язку таблиці з даними в fpt-файлі в кожному записі dbf-файлу memo-полю відводиться 10 байт, в які заноситься номер першого блоку даних. Причому номер зберігається в символьному вигляді з провідними пробілами. Наприклад, для вказівки на блок 8 дане поле буде містити значення «8» (в шістнадцятковому вигляді «20 20 20 20 20 20 20 20 20 38», де 38 - ASCII-код символу «8»). Нумерація блоків йде від початку файлу, тобто включає і заголовок.

Наприклад, при стандартній довжині блоку 64 байта записи даних будуть починатися з блоку 8 (довжина заголовка 512, поділена на розмір блоку 64).

З чим доведеться боротися

Теоретично формат DBF дозволяє зберігати в поле типу memo до 4 Гб даних. Однак на практиці через внутрішні обмежень FoxPro на довжину рядка оперувати з полями понад 65504 символів стає проблематично. На практиці довжина цього поля рідко перевищує кілька тисяч символів. Тому цілком допустимо вважати, що дані з поля типу memo можуть бути розміщені в поле типу text таблиці PostgreSQL (максимальне значення поля - 1 Гб). Так що розміри полів проблемою вважати не будемо.

Складніше то, що memo-поля можуть містити різноманітні символи, включаючи символ перекладу рядка. Оскільки при обробці текстового файлу PostgreSQL сприймає цей символ як роздільник записів, то необхідно подбати про його екранування. Причому в разі формату кінця рядка в стилі DOS (CR + LF) екранувати потрібно як символ перекладу рядка (0x0D), так і символ повернення каретки (0x0A).

Реалізація на FoxPro

FoxPro працює з memo-полями прозоро, так що ніяких зусиль з боку програміста не вимагається. Не забудьте поставити символ «» перед символами-роздільниками:

Лістинг 1. Файл memo2pg.prg (FoxPro)

use wmem Відкриваємо таблицю з memo-полями

m.delimiter = chr (9) символ Tab

* Текстове поле - екрануючи роздільники і символ «\»

m.descr = strtran (m.descr, m.delimiter,;

* У memo-поле додатково екрануючи символи кінця рядка (ASCII-коди 10 і 13)

m.memfld = strtran (m.memfld, m.delimiter,;

m.memfld = strtran (m.memfld, chr (13),;

m.memfld = strtran (m.memfld, chr (10),;

* Записуємо результат в файл, розділяючи поля символом, що зберігаються в змінної m.delimiter

wait window 'Finished.'

Малюнок. Робоче вікно FoxPro

Якщо ви вирішите працювати з CSV-форматом, то замість табуляції як роздільник буде використовуватися кома, а кожне поле даних, незалежно від типу, потрібно буде оточити сімволом- «лапками», наприклад «" », який використовується за умовчанням. Ну і всередині полів все «лапки» повинні бути подвоєні, щоб виключити їх спеціальну інтерпретацію.

Реалізація на Python

А ось тут нам доведеться застосувати всі накопичені вище знання за форматом файлів DBF і FPT. Оскільки повністю сценарій розбору DBF-файлу приводився в минулій статті, тут обмежимося тільки тією частиною, яка відповідає за отримання даних з мемо-поля. За основу взято сценарій dbf2pg.py, розглянутий в попередній статті (див. Лістинг 2). У нього додана обробка полів типу «M» в цикл, що обробляє кожну запис (відповідні рядки виділені червоним шрифтом):

Лістинг 2. Фрагмент сценарію dbf2pg.py, додані рядки

for i in range (num):

if fields [i] .type == 'M':

if fields [i] .type == 'D':

fld = fld [: 4] + '-' + fld [4: 6] + '-' + fld [6:]

Тут при виявленні поля типу memo лічений значення трактується як що містить номер першого блоку даних, і викликається функція розбору fpt-файлу:

Лістинг 3. Фрагмент сценарію dbf2pg.py, функція memo2pg

# Номер блоку перетворимо в число

fpt = open (basetabname + '.fpt', 'rb')

# Прочитуємо розмір блоку

blocksize = int (ord (fpt.read (1)) * 256 + ord (fpt.read (1)))

# Зміщується до початку блоку даних

# Прочитуємо розмір поля даних

fieldsize = ord (fpt.read (1)) * 16777216 + ord (fpt.read (1)) * 65536 + ord (fpt.read (1)) * 256 + ord (fpt.read (1))

# Перекодування, екранування тощо.

data = unicode (data, 'cp866'). encode ( 'koi8-r')

data = data.replace ( '\ x0A', '\\' + '\ x0A')

data = data.replace ( '\ x0D', '\\' + '\ x0D')

data = data.replace (delimiter, '\\' + delimiter)

Нарешті, потрібно подбати, щоб Python і не виконує жодних символи перекладу рядка самостійно, для чого замість виведення кожної сформованої рядки за допомогою оператора print ми будемо здійснювати запис в файл, відкритий в довічним режимі, і формувати кінець рядка вручну так, як нам потрібно:

Лістинг 4. Фрагмент сценарію dbf2pg.py, запис рядка в файл

В результаті dbf2pg.py тепер може обробляти і memo-поля.

Мова FoxPro надає розвинені засоби для роботи зі своїми файлами (виглядало б дивно, якби це було не так), і здійснити конвертацію файлу DBF в інший формат c його допомогою - справа кількох рядків коду. Однак не біда, якщо ви не дуже дружні з ним або не можете ним скористатися з якихось причин. Двійковий формат DBF, як ви могли переконатися, досить простий і зручний. Так що при необхідності реалізувати його обробку наявними підручними засобами праці не складе.

Схожі статті