При программной выгрузке данных в текстовые форматы разработчики нередко сталкиваются с ситуацией, когда готовый файл при открытии в блокноте или табличном редакторе отображает знаки вопроса («???») вместо кириллицы. Разберем механизм возникновения этой ошибки и выясним, как правильно управлять кодировками при формировании файлов формата CSV средствами платформы 1С:Предприятие.
Выясним причину такого поведения. Вопросительные знаки в тексте свидетельствуют о том, что данные были безвозвратно искажены именно в момент создания и записи файла, а не при его открытии. Рассмотрим исходный фрагмент кода, который приводит к подобной ошибке:
Функция ЗаписатьCSV(Текст, ИмяФайла)
Кодировка = КодировкаТекста.ANSI;
ТекстовыйФайлЗапись = Новый ЗаписьТекста(ИмяФайла, Кодировка);
ТекстовыйФайлЗапись.ЗаписатьСтроку(Текст);
ТекстовыйФайлЗапись.Закрыть();
Возврат 0;
КонецФункции
Проанализируем работу свойства КодировкаТекста.ANSI. Данное перечисление сообщает платформе, что нужно использовать системную кодовую страницу операционной системы по умолчанию (Active Code Page). Если код выгрузки выполняется на стороне сервера (директива &НаСервере) под управлением Windows с англоязычной локалью по умолчанию (например, windows-1252) или на сервере под управлением Linux, кириллические символы в активной кодовой таблице отсутствуют. При попытке преобразовать строку Юникод в однобайтную таблицу операционная система заменяет все неизвестные ей символы байтом 0x3F, то есть знаком вопроса. В результате исходные данные утрачиваются навсегда.
Если принимающая сторона требует однобайтовую кодировку Windows (кириллица), нельзя полагаться на системное значение КодировкаТекста.ANSI. Конструктор объекта ЗаписьТекста вторым параметром принимает не только предопределенные элементы перечисления, но и точное строковое обозначение необходимой кодовой страницы.
Посмотрим на пример выгрузки с явным заданием кодировки windows-1251:
Функция ЗаписатьCSVВКодировке1251(Текст, ИмяФайла)
// Явно указываем кодировку строкой для исключения зависимости от настроек сервера
ТекстовыйФайлЗапись = Новый ЗаписьТекста(ИмяФайла, "windows-1251");
ТекстовыйФайлЗапись.ЗаписатьСтроку(Текст);
ТекстовыйФайлЗапись.Закрыть();
КонецФункции
В этом случае платформа принудительно преобразует символы по таблице windows-1251 независимо от региональных настроек сервера или операционной системы пользователя.
Современным стандартом обмена данными является использование Юникода. Платформа 1С поддерживает запись файлов в кодировке UTF-8. Рассмотрим, как применить это решение на практике:
Функция ЗаписатьCSVВКодировкеUTF8(Текст, ИмяФайла)
Кодировка = КодировкаТекста.UTF8;
ТекстовыйФайлЗапись = Новый ЗаписьТекста(ИмяФайла, Кодировка);
ТекстовыйФайлЗапись.ЗаписатьСтроку(Текст);
ТекстовыйФайлЗапись.Закрыть();
КонецФункции
Разберем важный нюанс при использовании КодировкаТекста.UTF8 с объектом ЗаписьТекста:
ЗаписьТекста добавляет в самое начало файла специальный трехбайтовый маркер последовательности байтов — BOM (Byte Order Mark, EF BB BF).Если для интеграции требуется строгий формат UTF-8 без BOM, объект ЗаписьТекста не позволяет отключить его запись напрямую. В таком случае воспользуемся альтернативным платформенным механизмом преобразования строки в двоичные данные:
Процедура ЗаписатьCSVБезBOM(Текст, ИмяФайла)
// Четвертый параметр (Ложь) отключает добавление метки порядка байтов (BOM)
ДвоичныеДанные = ПолучитьДвоичныеДанныеИзСтроки(Текст, КодировкаТекста.UTF8, ПорядокБайтов.Прямой, Ложь);
ДвоичныеДанные.Записать(ИмяФайла);
КонецПроцедуры
Рассмотрим альтернативные способы формирования файлов CSV, если ручное построчное наполнение через ЗаписьТекста не требуется:
ТекстовыйДокумент: Позволяет быстро записать накопленный текстовый массив с явным заданием нужной кодировки:
ТекстДок = Новый ТекстовыйДокумент;
ТекстДок.УстановитьТекст(Текст);
ТекстДок.Записать(ИмяФайла, "windows-1251");
ТабличныйДокумент: Если отчет или данные выгрузки уже выводятся в табличную форму, их можно сохранить в CSV без ручного перебора ячеек:
ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.CSV);
При выгрузке текстовых файлов обратим внимание на следующие технические детали:
ЗаписьТекста третий параметр конструктора задает разделитель строк. По умолчанию он зависит от операционной системы. Для кроссплатформенной надежности и корректного чтения в Excel рекомендуется явно передавать стандартный разделитель Символы.ВК + Символы.ПС (CRLF)."").