При выгрузке данных из 1С в текстовые форматы (CSV, TXT) разработчики нередко сталкиваются с непонятным поведением сторонних программ: в коде платформы 1С явно указывается кодировка windows-1251, однако текстовый редактор Notepad++ или принимающая сторона у заказчика упорно определяют сформированный файл как UTF-8. Разберем по шагам, почему так происходит, как текстовые редакторы определяют кодировку и как гарантировать правильное сохранение файла в 1С.
Проанализируем структуру текстовых файлов. В стандартном текстовом файле (без специальных меток вроде BOM) отсутствует метаинформация о том, в какой именно кодировке он записан. Программы для просмотра текста (включая Notepad++) определяют кодировку исключительно эвристическим путем — анализируя последовательность байтов в содержимом файла.
В современных кодировках первые 128 символов (байты от 0x00 до 0x7F) стандартизированы таблицей US-ASCII. К ним относятся:
В кодировке Windows-1251 эти символы кодируются ровно одним байтом со значением меньше 128. В кодировке UTF-8 эти же самые символы кодируются в точности теми же самыми однобайтными значениями. Таким образом, если выгружаемый файл состоит только из латинских букв, цифр и стандартных разделителей, его побайтовое представление в Windows-1251 и в UTF-8 без BOM является на 100% идентичным.
Встретив поток байтов, где нет ни одного значения старше 0x7F, текстовый редактор Notepad++ физически не может отличить Windows-1251 от UTF-8 или чистой ASCII. По умолчанию большинство современных редакторов и библиотек считают такой файл кодировкой UTF-8 (или ориентируются на системные настройки нового документа). Как только в файл попадает хотя бы одна русская буква (ее код в Windows-1251 превышает 127), эвристический анализатор сразу же распознает файл как ANSI / Windows-1251, поскольку в UTF-8 одиночный байт из верхнего диапазона считается недопустимым.
Посмотрим на типичный фрагмент кода выгрузки через объект ТекстовыйДокумент и разберем важные технические нюансы платформы 1С:
Текст = Новый ТекстовыйДокумент;
Текст.УстановитьТипФайла("windows-1251");
Текст.ДобавитьСтроку("CODE;AMOUNT;DESCRIPTION");
Текст.Записать(ПутьКФайлу, "windows-1251");
Обратим внимание на следующие особенности:
УстановитьТипФайла() предназначен в первую очередь для интерактивного режима. Он указывает кодировку по умолчанию, которая будет выбрана, если пользователь интерактивно откроет документ и нажмет кнопку «Сохранить как...». При программном вызове метода Записать() определяющим является именно второй параметр метода — ТипФайла. Поэтому вызывать УстановитьТипФайла() перед программной записью не требуется.КодировкаТекста.ANSI на сервере. Значение системного перечисления КодировкаТекста.ANSI является платформозависимым. В среде ОС Windows оно действительно соответствует системной кодовой странице (в русской локализации — Windows-1251). Однако на серверах под управлением Linux системной локалью обычно является UTF-8. Если фоновое задание или серверный вызов на Linux использует КодировкаТекста.ANSI, файл фактически запишется в UTF-8. Чтобы избежать платформенных ошибок, всегда передавайте точное строковое имя кодировки: "windows-1251" или "cp1251".CRLF (символы 0x0D 0x0A), а на Linux — только LF (символ 0x0A). Некоторые внешние системы при несовпадении разделителей строк выдают общую ошибку структуры или кодировки файла. Для надежности передавайте разделитель строк третьим параметром метода Записать().Выясним, как быстро доказать заказчику или самому себе, что файл сохранен верно:
Windows-1251 (в строке состояния отобразится «ANSI» или «Windows-1251»). Это подтвердит, что алгоритм записи 1С работает абсолютно корректно.EF BB BF (маркер UTF-8 BOM). Если файла без кириллицы касается сторонний сервис, ожидающий Windows-1251, он обработает файл штатно, так как байты таблицы ASCII совпадают во всех однобайтовых кодировках и в UTF-8.Рассмотрим более производительные и надежные подходы к формированию файлов, исключающие хранение всего массива строк в оперативной памяти.
1. Использование объекта ЗаписьТекста
Объект ЗаписьТекста работает в потоковом режиме и идеально подходит для выгрузки больших объемов данных (выборок из запросов, CSV-файлов):
Разделитель = Символы.ВК + Символы.ПС; // Явное указание CRLF для Windows-совместимости
Запись = Новый ЗаписьТекста(Кат + ИмяФайла, "windows-1251", Разделитель);
Запись.ЗаписатьСтроку("OPERATION_DATE;AMOUNT;TRANSACTION_ID");
Пока Результат.Следующий() Цикл
СтрокаДанных = ДатаСтр + ";" + СуммаСтр + ";" + Транзакция;
Запись.ЗаписатьСтроку(СтрокаДанных);
КонецЦикла;
Запись.Закрыть();
2. Формирование двоичных данных без маркера BOM
Если необходимо гарантировать отсутствие нежелательных байтовых меток при программной передаче строки во внешние хранилища, используем преобразование строки в двоичные данные:
РезультирующийТекст = "OPERATION_DATE;AMOUNT;TRANSACTION_ID" + Символы.ПС;
// Третий параметр "Ложь" исключает запись маркера BOM
ДвоичныеДанныеФайла = ПолучитьДвоичныеДанныеИзСтроки(РезультирующийТекст, "windows-1251", Ложь);
ДвоичныеДанныеФайла.Записать(Кат + ИмяФайла);
Если ваш файл содержит исключительно латинские символы, цифры и стандартную пунктуацию, сообщение текстового редактора или заказчика о том, что файл представлен в кодировке UTF-8, является следствием совпадения байтовых представлений в диапазоне ASCII. Файл уже находится в кодировке Windows-1251. Чтобы закрыть разногласия с принимающей стороной, достаточно добавить для демонстрации любой кириллический символ или объяснить контрагенту принцип эвристического анализа кодировок в современных редакторах.