Как в 1С прочитать и записать DBF в нужной кодировке через VFPOLEDB?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При интеграции 1С со сторонними системами (например, устаревшими базами FoxPro 2.6 или DOS-приложениями) часто возникает проблема некорректного отображения кириллицы («кракозябры»). Это происходит при подключении через OLE DB провайдер VFPOLEDB.1 к файлам DBF, у которых в 29-м байте заголовка отсутствует метка кодовой страницы (значение 0x00 вместо 0x65 для кодировки CP866).

Если файл находится в сетевом совместном доступе и монопольно изменить его заголовок невозможно, параметры строки подключения вроде Collating Sequence=RUSSIAN или CODEPAGE=866 не заставляют драйвер автоматически декодировать строки. Разберем причины такого поведения и рассмотрим практические способы решения задачи чтения и записи данных.

Причина некорректного чтения неразмеченных таблиц

Проанализируем работу драйвера VFPOLEDB. Если 29-й байт равен 0x00, провайдер считает таблицу неразмеченной (unmarked). Параметр CODEPAGE в строке подключения определяет только кодовую страницу текущей сессии (CPCURRENT()), но не задает интерпретацию полей таблицы. Провайдер по умолчанию считает, что данные в неразмеченной таблице уже находятся в кодировке Windows ANSI (Windows-1251), и отдает их без перекодирования из OEM (CP866).

При этом вызов системной функции CPDBF() возвращает 0, так как кодовая страница у таблицы не задана явно в заголовке.

Решение 1. Использование функции CPCONVERT в SQL-запросах к VFPOLEDB

Поскольку автоматическое преобразование не срабатывает, применим явное перекодирование прямо в SQL-запросах через встроенную функцию FoxPro CPCONVERT(ИсходнаяКодировка, ЦелеваяКодировка, Выражение).

Так как кодовая страница источника нам известна (DOS / CP866), а в среду 1С через COM требуется передать Windows ANSI (Windows-1251), укажем эти кодовые страницы константами.

Чтение данных из таблицы DBF:


Соединение = Новый COMОбъект("ADODB.Connection");
СтрокаПодключения = "Provider=VFPOLEDB.1;Data Source=" + ПутьКаталогаDBF + ";Collating Sequence=MACHINE;EXCLUSIVE=NO;";
Соединение.Open(СтрокаПодключения);

// При выборке конвертируем поле из CP866 в CP1251
ТекстЗапроса = "SELECT Код, CPCONVERT(866, 1251, Наименование) AS Наименование FROM Справочник.DBF";
Команда = Новый COMОбъект("ADODB.Command");
Команда.ActiveConnection = Соединение;
Команда.CommandText = ТекстЗапроса;

Выборка = Команда.Execute();
Пока Выборка.EOF = 0 Цикл
    Код = Выборка.Fields("Код").Value;
    Наименование = Выборка.Fields("Наименование").Value;
    // Значение получено в корректной кириллической кодировке Windows-1251
    Выборка.MoveNext();
КонецЦикла;

Соединение.Close();

Запись и обновление данных в режиме совместного доступа:

При выполнении команд INSERT или UPDATE выполняем зеркальное преобразование — из кодировки 1251 в кодировку 866:


// Добавление новой записи с перекодированием
ТекстЗапроса = "INSERT INTO Справочник.DBF (Код, Наименование) VALUES ('001', CPCONVERT(1251, 866, 'Тестовый товар'))";
Соединение.Execute(ТекстЗапроса);

// Обновление существующей записи
ТекстОбновления = "UPDATE Справочник.DBF SET Наименование = CPCONVERT(1251, 866, 'Новое наименование') WHERE Код = '001'";
Соединение.Execute(ТекстОбновления);

Решение 2. Управление преобразованием через системную функцию SYS(3101)

В провайдере VFPOLEDB предусмотрена системная функция SYS(3101), которая управляет кодовой страницей трансляции для строк, возвращаемых через интерфейсы COM/OLE DB. Выполним вызов этой функции сразу после открытия соединения:


Соединение = Новый COMОбъект("ADODB.Connection");
Соединение.Open("Provider=VFPOLEDB.1;Data Source=" + ПутьКаталогаDBF + ";Collating Sequence=MACHINE;EXCLUSIVE=NO;");

// Принудительно задаем кодовую страницу COM-интерфейса 866
Соединение.Execute("SYS(3101, 866)");

// После этого выборку можно выполнять стандартным запросом
Выборка = Соединение.Execute("SELECT Код, Наименование FROM Справочник.DBF");

Решение 3. Использование штатного объекта 1С «XBase»

Если структура DBF-файла соответствует стандартному формату dBase / FoxPro 2.6 и не содержит специфических расширений Visual FoxPro (таких как системные автоинкременты или поля Blob), наиболее простым и надежным решением является встроенный объект платформы 1С XBase.

Объект XBase позволяет явно указать кодировку при открытии таблицы и поддерживает многопользовательский режим работы:


ФайлDBF = Новый XBase;
// Явно указываем кодировку DOS (OEM / CP866)
ФайлDBF.Кодировка = КодировкаXBase.OEM;

// Открываем файл в разделенном режиме
ФайлDBF.ОткрытьФайл(ПутьКФайлуDBF, ПутьКФайлуИндексаCDX, Ложь);

Если ФайлDBF.Открыта() Тогда
    // Чтение данных
    ФайлDBF.Первая();
    Пока НЕ ФайлDBF.ВКонце() Цикл
        ТекНаименование = ФайлDBF.Наименование;
        ФайлDBF.Следующая();
    КонецЦикла;

    // Добавление новой записи
    ФайлDBF.Добавить();
    ФайлDBF.Код = "002";
    ФайлDBF.Наименование = "Новый элемент";
    ФайлDBF.Записать();

    ФайлDBF.ЗакрытьФайл();
КонецЕсли;

Решение 4. Подключение через Advantage Database Server / ODBC

Если требуется высокая скорость обработки больших таблиц с CDX-индексами FoxPro 2.6 в разделенном режиме, можно использовать драйвер Advantage ODBC Driver. В строке подключения явно определяются параметры кодовой страницы OEM:


Соединение = Новый COMОбъект("ADODB.Connection");
СтрокаПодключения = "Driver={Advantage StreamlineSQL ODBC};"
    + "DataDirectory=" + ПутьКаталогаDBF + ";"
    + "DefaultType=FoxPro;"
    + "ServerTypes=1;"
    + "AdvantageLocking=OFF;"
    + "CharSet=OEM;"
    + "Language=OEM;"
    + "Locking=RECORD;";

Соединение.Open(СтрокаПодключения);
Выборка = Соединение.Execute("SELECT * FROM Справочник");

Важные замечания по разрядности платформы (32-bit и 64-bit)

  1. Провайдер VFPOLEDB.1 существует только в 32-разрядном исполнении.
  2. При выполнении кода на 64-разрядном сервере 1С:Предприятия или в 64-разрядном клиенте попытка создать объект Новый COMОбъект("ADODB.Connection") с данным провайдером завершится ошибкой («Класс не зарегистрирован»).
  3. Для работы на 64-разрядной платформе рекомендуется использовать встроенный объект XBase, переносить вызовы 32-битного OLE DB в пул приложений COM+ (dllhost.exe) или использовать 64-разрядные ODBC-драйверы.
← На главную