Реинкарнация данных II: memo-поля::Журнал СА 5.2005
www.samag.ru
Льготная подписка для студентов      
Поиск   
              
 www.samag.ru    Web  0 товаров , сумма 0 руб.
E-mail
Пароль  
 Запомнить меня
Регистрация | Забыли пароль?
О журнале
Журнал «БИТ»
Подписка
Где купить
Авторам
Рекламодателям
Магазин
Архив номеров
Вакансии
Контакты
   

Jobsora


  Опросы

Какие курсы вы бы выбрали для себя?  

Очные
Онлайновые
Платные
Бесплатные
Я и так все знаю

 Читать далее...

1001 и 1 книга  
28.05.2019г.
Просмотров: 2249
Комментарии: 2
Анализ вредоносных программ

 Читать далее...

28.05.2019г.
Просмотров: 2226
Комментарии: 1
Микросервисы и контейнеры Docker

 Читать далее...

28.05.2019г.
Просмотров: 1784
Комментарии: 0
Django 2 в примерах

 Читать далее...

28.05.2019г.
Просмотров: 1309
Комментарии: 0
Введение в анализ алгоритмов

 Читать далее...

27.03.2019г.
Просмотров: 1840
Комментарии: 1
Arduino Uno и Raspberry Pi 3: от схемотехники к интернету вещей

 Читать далее...

Друзья сайта  

Форум системных администраторов  

sysadmins.ru

 Реинкарнация данных II: memo-поля

Архив номеров / 2005 / Выпуск №5 (30) / Реинкарнация данных II: memo-поля

Рубрика: Базы данных /  Оптимизация

СЕРГЕЙ СУПРУНОВ

Реинкарнация данных II: memo-поля

В прошлом номере журнала (см. №4 за 2005 г.) мы рассмотрели несколько способов переноса данных из таблиц формата DBF в PostgreSQL. Однако чтобы не перегружать статью, вопрос работы с полями типа memo, достаточно широко используемыми в FoxPro, был оставлен без внимания. Теперь пришло время восполнить данный пробел.

Формат memo-полей

Если нужно сохранить в одном поле данные большого или неопределенного объема, в FoxPro (как и в некоторых других СУБД) используются поля специального типа – так называемые memo-поля. Данные такого поля физически сохраняются в отдельном файле (в случае с FoxPro он имеет то же имя, что и dbf-файл, но с расширением fpt). Логически мемо-поля связываются с таблицей таким образом, что доступны, как и любое другое поле текущей записи.

Файл fpt для упрощения работы с данными хранит их поблочно. Размер блока по умолчанию в FPD 2.6 составляет 64 байта. Заголовок fpt-файла имеет размер 512 байт, структура его следующая:

Таблица. Структура заголовка fpt-файла

Смещение

Длина поля

Назначение

0

4

Номер следующего свободного блока

4

2

Не используется

6

2

Размер блока

8

504

Не используется

Начиная с 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).

Можно использовать формат CSV для загрузки в PostgreSQL – в этом случае значением поля будут считаться все символы, заключенные в «кавычки». «Кавычками» в данном случае может выступать любой символ, он задается как параметр команды COPY. Теперь внутри поля нужно экранировать «кавычки» (путем удвоения), однако в данном случае больше шансов найти подходящий символ, мало используемый внутри поля данных. К тому же исключаются проблемы с различными стилями перевода строки.

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

FoxPro работает с memo-полями прозрачно, так что никаких усилий со стороны программиста не требуется. Не забудьте поставить символ «» перед символами-разделителями:

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

close databases

* Это – комментарий с начала строки

&& А так выделяются комментарии в произвольном месте строки

use wmem    && Открываем таблицу с memo-полями

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

m.txf = fcreate('memo2pg.txt')

scan

* Текстовое поле – экранируем разделители и символ «\»

    m.descr = strtran(Descr, '\', '\\')

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

                                 '\' + m.delimiter)

* В memo-поле дополнительно экранируем символы конца строки (ASCII-коды 10 и 13)

    m.memfld = strtran(Memfld, '\', '\\')

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

                                 '\' + m.delimiter)

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

                                 '\' + chr(13))

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

                                 '\' + chr(10))

* Записываем результат в файл, разделяя поля символом, хранящимся в переменной m.delimiter

    =fputs(m.txf, m.descr + ;

                   m.delimiter + ;

                   m.memfld)

endscan

=fclose(m.txf)

wait window 'Finished.'

Рисунок. Рабочее окно FoxPro

Рисунок. Рабочее окно FoxPro

Если вы решите работать с CSV-форматом, то вместо табуляции в качестве разделителя будет использоваться запятая, а каждое поле данных, независимо от типа, нужно будет окружить символом-«кавычкой», например «”», который используется по умолчанию. Ну и внутри полей все «кавычки» должны быть удвоены, чтобы исключить их специальную интерпретацию.

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

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

Листинг 2. Фрагмент сценария dbf2pg.py, добавленные строки

.. .. ..

                 for i in range(num):

                        fld = dbf.read(fields[i].len)

           # Добавлено: vvvvvvv

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

                               fld = memo2pg(fld)

           # ----------^^^^^^^

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

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

.. .. ..

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

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

def memo2pg(startblock):

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

    startblock = int(startblock)

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

    fpt.read(6)

# Считываем размер блока

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

# Смещаемся к началу блока данных

    fpt.seek(blocksize * startblock)

    fpt.read(4)

# Считываем размер поля данных

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

# Читаем данные

    data = fpt.read(fieldsize)

    fpt.close()

# Перекодировка, экранирование и проч.

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

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

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

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

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

    return data

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

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

.. .. ..

           #      print line[:-1]

                 outfile.write(line[:-1] + '\r\n')

.. .. ..

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

Заключение

Язык FoxPro предоставляет развитые средства для работы со своими файлами (выглядело бы странно, если бы это было не так), и осуществить конвертирование файла DBF в другой формат c его помощью – дело нескольких строк кода. Однако не беда, если вы не очень дружны с ним или не можете им воспользоваться по каким-то причинам. Двоичный формат DBF, как вы могли убедиться, достаточно прост и удобен. Так что при необходимости реализовать его обработку имеющимися подручными средствами труда не составит.


Комментарии отсутствуют

Добавить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

               Copyright © Системный администратор

Яндекс.Метрика
Tel.: (499) 277-12-41
Fax: (499) 277-12-45
E-mail: sa@samag.ru