Как изменить кодировку файла из UTF-8 в ANSI в 1С без появления кракозябр

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

В процессе интеграции 1С с внешними информационными системами разработчики часто сталкиваются с необходимостью конвертации текстовых файлов и XML-документов из кодировки UTF-8 в ANSI (в русскоязычном сегменте это кодовая страница Windows-1251). Казалось бы, задача тривиальная, но на практике она нередко приводит к появлению нечитаемых символов — так называемых «кракозябр» (модзибакэ). Символы кириллицы превращаются в странные буквосочетания вида "Отсутствует" вместо слова "Отсутствует".

В этой статье мы подробно разберем, почему возникает эта проблема, проанализируем физические причины сбоя кодировок и рассмотрим несколько надежных способов перекодирования файлов в среде 1С:Предприятие.

Выясняем причину: почему ломается кодировка при чтении

Прежде чем перейти к написанию кода, давайте разберем физическую суть проблемы. Кодировка UTF-8 является многобайтовой: для кодирования латинских символов используется 1 байт, а для символов кириллицы — 2 байта. Кодировка ANSI (она же Windows-1251) — однобайтовая, где каждому символу соответствует ровно 1 байт.

Например, русская заглавная буква "О" в UTF-8 кодируется двумя байтами: D0 и 9E. Если платформа 1С пытается прочитать файл как ANSI, она интерпретирует эти два байта как два отдельных независимых символа. В кодовой таблице Windows-1251 байт D0 соответствует букве "Р", а байт 9E — символу "ћ". Именно так буква "О" превращается в "Рћ".

Главная ошибка разработчиков заключается в том, что при чтении файла они не указывают его исходную кодировку. Если в файле UTF-8 отсутствует специальная метка порядка байтов — BOM (Byte Order Mark), то платформа 1С по умолчанию считывает его в системной кодировке по умолчанию (которая на русских Windows-системах как раз и является ANSI). В результате в оперативную память 1С загружается уже испорченный текст. Последующая запись этого текста с указанием кодировки ANSI лишь сохраняет эти «кракозябры» в новый файл.

Золотое правило перекодирования: чтобы успешно записать файл в новой кодировке, его сначала необходимо абсолютно корректно прочитать в исходной кодировке.

Способ 1. Использование объекта ТекстовыйДокумент

Рассмотрим простейший классический способ решения проблемы с использованием объекта ТекстовыйДокумент. Этот метод отлично подходит для небольших файлов. Разберем по шагам правильную последовательность действий.

Для того чтобы 1С не пыталась угадать кодировку файла без BOM, мы обязаны явно передать вторым параметром метода Прочитать системное перечисление КодировкаТекста.UTF8.


ПутьКИсточнику = ОбъектС.Каталог + "\456.xml";
ПутьКПриемнику = ОбъектС.Каталог + "\457.txt";

ТекстДокумент = Новый ТекстовыйДокумент;

// Шаг 1. Явно указываем кодировку UTF-8 при чтении файла
ТекстДокумент.Прочитать(ПутьКИсточнику, КодировкаТекста.UTF8);

// Шаг 2. Записываем файл в кодировке ANSI
ТекстДокумент.Записать(ПутьКПриемнику, КодировкаТекста.ANSI);

При таком подходе платформа считает двухбайтовые последовательности UTF-8 как единые символы кириллицы, корректно разместит их в памяти в формате Unicode, а при вызове метода Записать преобразует их в однобайтовую кодировку Windows-1251 без каких-либо потерь для русского текста.

Способ 2. Использование потоковых объектов ЧтениеТекста и ЗаписьТекста

Если вам приходится работать с файлами больших размеров (от нескольких десятков мегабайт и выше), использование объекта ТекстовыйДокумент может привести к значительному потреблению оперативной памяти и замедлению работы системы. В таких сценариях мы рекомендуем использовать более легковесные потоковые объекты — ЧтениеТекста и ЗаписьТекста.

Проанализируем пример кода, реализующий эту логику:


ПутьКИсточнику = ОбъектС.Каталог + "\456.xml";
ПутьКПриемнику = ОбъектС.Каталог + "\457.txt";

// Шаг 1. Открываем поток чтения с явным указанием UTF-8
ФайлЧтения = Новый ЧтениеТекста(ПутьКИсточнику, КодировкаТекста.UTF8);
ВесьТекст = ФайлЧтения.Прочитать();
ФайлЧтения.Закрыть();

// Шаг 2. Открываем поток записи в кодировке ANSI
ФайлЗаписи = Новый ЗаписьТекста(ПутьКПриемнику, КодировкаТекста.ANSI);
ФайлЗаписи.Записать(ВесьТекст);
ФайлЗаписи.Закрыть();

Данный метод работает быстрее, так как не производит лишнего анализа структуры строк внутри объекта 1С и напрямую перекачивает данные через буфер памяти.

Способ 3. Перекодирование XML-документов с заменой заголовка

Если исходный файл является документом XML, то простая перезапись его байтов в формате ANSI решает проблему лишь наполовину. Обратите внимание на первую строку стандартного XML-документа:

<?xml version="1.0" encoding="UTF-8"?>

Если вы просто сохраните этот файл в кодировке ANSI, текст заголовка останется прежним. Внешняя программа (например, веб-сервис, банк-клиент или государственная система учета), принимающая этот файл, прочитает заголовок, увидит инструкцию encoding="UTF-8" и начнет парсить однобайтовые символы Windows-1251 по правилам UTF-8. Это неизбежно приведет к ошибке разбора XML-структуры.

Поэтому при конвертации XML-файлов нам необходимо выполнить программную замену кодировки в самом тексте декларации. Посмотрим, как это сделать:


ПутьКИсточнику = ОбъектС.Каталог + "\456.xml";
ПутьКПриемнику = ОбъектС.Каталог + "\457.xml";

// Читаем исходный файл XML в UTF-8
ТекстДок = Новый ТекстовыйДокумент;
ТекстДок.Прочитать(ПутьКИсточнику, КодировкаТекста.UTF8);
ТекстФайла = ТекстДок.ПолучитьТекст();

// Выполняем замену декларации кодировки в заголовке
ТекстФайла = СтрЗаменить(ТекстФайла, "encoding=""UTF-8""", "encoding=""windows-1251""");
ТекстФайла = СтрЗаменить(ТекстФайла, "encoding=""utf-8""", "encoding=""windows-1251""");

// Записываем измененный текст в формате ANSI
ТекстДок.УстановитьТекст(ТекстФайла);
ТекстДок.Записать(ПутьКПриемнику, КодировкаТекста.ANSI);

Способ 4. Использование специализированных объектов ЧтениеXML и ЗаписьXML

Наиболее красивым, профессиональным и безопасным способом работы с XML-документами является использование объектной модели 1С для работы с XML. Объекты ЧтениеXML и ЗаписьXML берут на себя всю рутину по чтению схем, кодированию спецсимволов и автоматическому формированию заголовков.

Давайте рассмотрим пример, в котором мы последовательно читаем узлы исходного XML-файла и записываем их в новый файл с автоматической сменой кодировки:


ПутьКИсточнику = ОбъектС.Каталог + "\456.xml";
ПутьКПриемнику = ОбъектС.Каталог + "\457.xml";

// Создаем объект чтения. Он автоматически определит кодировку по заголовку XML
ФайлXMLЧтение = Новый ЧтениеXML;
ФайлXMLЧтение.ОткрытьФайл(ПутьКИсточнику);

// Создаем объект записи с явным указанием кодировки Windows-1251
ФайлXMLЗапись = Новый ЗаписьXML;
ПараметрыЗаписи = Новый ПараметрыЗаписиXML("windows-1251", "1.0");
ФайлXMLЗапись.ОткрытьФайл(ПутьКПриемнику, ПараметрыЗаписи);

// Записываем заголовок 
ФайлXMLЗапись.ЗаписатьОбъявлениеXML();

// Посимвольно переносим структуру XML-документа
Пока ФайлXMLЧтение.Прочитать() Цикл
    ФайлXMLЗапись.ЗаписатьТекущий(ФайлXMLЧтение);
КонецЦикла;

// Закрываем потоки
ФайлXMLЧтение.Закрыть();
ФайлXMLЗапись.Закрыть();

Этот способ гарантирует, что структура вашего XML-документа не будет нарушена, а заголовок файла будет строго соответствовать его фактической кодировке байтов.

Важные нюансы и ограничения при работе с ANSI

При решении задач перекодирования важно учитывать несколько неочевидных технических моментов, которые могут повлиять на стабильность работы вашей интеграции:

  1. Различия операционных систем (Windows и Linux). Если ваш сервер приложений 1С работает под управлением ОС Linux, использование предопределенного значения КодировкаТекста.ANSI может дать непредсказуемый результат. Системная кодировка по умолчанию в Linux-системах обычно совпадает с UTF-8, поэтому платформа может вообще не выполнить конвертацию. Для кроссплатформенного кода безопаснее указывать название кодировки строкой, например, "windows-1251" или "cp1251", если это поддерживается используемым методом 1С.
  2. Потеря уникальных символов UTF-8. Помните, что кодовое пространство UTF-8 включает в себя практически все символы существующих языков мира, спецсимволы и эмодзи. Пространство ANSI (Windows-1251) ограничено всего 256 символами. Если в вашем исходном XML-файле содержались специфические символы (например, умлауты, специфические знаки валют или стрелки), при записи в ANSI они будут безвозвратно утеряны и автоматически заменены на знаки вопроса ?. Постарайтесь заранее очистить или заменить такие символы перед записью.
  3. Byte Order Mark (BOM). При записи файлов в ANSI метка порядка байтов BOM никогда не используется. Если вы столкнетесь с необходимостью записать файл обратно в UTF-8, учитывайте требования принимающей стороны: некоторым старым системам критически важно отсутствие BOM-символов в начале файла.

Применяя данные подходы и учитывая описанные правила, вы сможете навсегда избавиться от проблем с кодировками файлов и обеспечить надежный обмен данными между вашими базами 1С и внешними программными продуктами.

← На главную