При интеграции 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, так как кодовая страница у таблицы не задана явно в заголовке.
Поскольку автоматическое преобразование не срабатывает, применим явное перекодирование прямо в 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(ТекстОбновления);
В провайдере 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");
Если структура 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.ЗакрытьФайл();
КонецЕсли;
Если требуется высокая скорость обработки больших таблиц с 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 Справочник");
VFPOLEDB.1 существует только в 32-разрядном исполнении.Новый COMОбъект("ADODB.Connection") с данным провайдером завершится ошибкой («Класс не зарегистрирован»).XBase, переносить вызовы 32-битного OLE DB в пул приложений COM+ (dllhost.exe) или использовать 64-разрядные ODBC-драйверы.