Кодировка текстового файла в 1С: проверяем байты и читаем без кракозябр
Содержание
Кодировку файла узнают по его первым байтам и по тому, какие байты встречаются в тексте. EF BB BF в начале — это UTF-8 с меткой BOM. FF FE — UTF-16. Если метки нет, файл проверяют на корректность UTF-8. Не прошёл проверку — почти наверняка Windows-1251 или, для старых DOS-выгрузок, CP866. В 1С 8.3 такую проверку пишут на встроенном языке через буфер двоичных данных, а результат передают в ТекстовыйДокумент.Прочитать() или ЧтениеТекста.
Типичная ситуация: банк, маркетплейс или коллега прислали CSV, обработка загрузки отработала без ошибок, а в справочнике контрагентов появились «РћРћРћ Ромашка». Файл прочитан не в той кодировке. Ниже — как узнать кодировку файла руками за минуту, как определить её программно в 1С и как исправить чтение, конвертацию, CSV и XML.
Как определить кодировку файла без программирования
Прежде чем писать код, проверьте один конкретный файл вручную. Так вы поймёте, с чем имеете дело, и сможете проверить свой алгоритм.
| Инструмент | Где смотреть | Что покажет |
|---|---|---|
| Блокнот Windows 10/11 | строка состояния внизу справа | «UTF-8», «UTF-8 с BOM», «ANSI», «UTF-16 LE» |
| Notepad++ | меню Кодировки (Encoding), отмечен текущий вариант | кодировку и наличие BOM, можно переключить и сразу увидеть результат |
| VS Code | строка состояния, справа | кодировку; по клику — «Reopen with Encoding» |
| PowerShell | Format-Hex -Path .\file.csv | шестнадцатеричный дамп: видно BOM и байты кириллицы |
| Linux | file -bi file.csv | text/plain; charset=utf-8 или charset=iso-8859-1 |
Последний пункт с подвохом. Утилита file не знает Windows-1251 и для кириллицы в этой кодировке часто пишет iso-8859-1 или unknown-8bit. Читайте это как «однобайтовая, не UTF-8».
«ANSI» в Блокноте на русской Windows — это Windows-1251. Именно в ней Excel по умолчанию сохраняет CSV, а 1С называет её КодировкаТекста.ANSI.
Почему 1С читает файл кракозябрами
Сам файл почти никогда не «битый». Байты в нём правильные, но программа сопоставляет им символы по другой таблице. По виду мусора можно сразу догадаться, какая пара кодировок перепутана.
| Что видно вместо «Привет» | Файл в кодировке | Прочитан как |
|---|---|---|
Привет | UTF-8 | Windows-1251 |
������ или пустые квадраты | Windows-1251 | UTF-8 |
ЏаЁўҐв | CP866 | Windows-1251 |
п»їПривет в начале первой строки | UTF-8 с BOM | Windows-1251 |
| Пробелы или нули между буквами | UTF-16 | однобайтовая |
Откуда берутся такие ошибки при обмене данными:
- 📤 Источник сменил кодировку. Сайт или маркетплейс перешёл на UTF-8, а обработка загрузки по-прежнему читает в
ANSI. - 💾 Пересохранение в Excel. Пользователь открыл CSV, поправил ячейку, нажал «Сохранить» — UTF-8 превратился в Windows-1251.
- 🧾 Старое ПО и оборудование. Кассовые программы, банк-клиенты и DOS-утилиты до сих пор выгружают в CP866.
- 🔤 Жёстко прописанная кодировка в коде. Разработчик однажды указал
КодировкаТекста.UTF8, и с тех пор все файлы читаются только так. - 🏷 Неверная декларация в XML. В заголовке написано
encoding="windows-1251", а файл сохранён в UTF-8.
Чтение файла в 1С с явным указанием кодировки
Главное правило: не полагайтесь на то, что платформа угадает кодировку сама. Автоопределение надёжно работает только при наличии BOM. Для файла без метки всегда передавайте кодировку явно.
В 1С кодировку задают двумя способами:
- Значением системного перечисления
КодировкаТекста:UTF8,ANSI(Windows-1251 на русской системе),OEM(CP866),UTF16,Системная. - Строкой с именем кодировки:
"utf-8","windows-1251","cp866","koi8-r".
Строка удобнее, когда кодировку определяет код или она хранится в настройках. И она не зависит от языковых настроек сервера: ANSI на сервере с английской локалью может оказаться вовсе не 1251.
Чтение целиком через текстовый документ:
ТекстДок = Новый ТекстовыйДокумент;
ТекстДок.Прочитать(ИмяФайла, "windows-1251");
Для НомерСтроки = 1 По ТекстДок.КоличествоСтрок() Цикл
Строка = ТекстДок.ПолучитьСтроку(НомерСтроки);
// разбор строки
КонецЦикла;
Построчное чтение большого файла через ЧтениеТекста — оно не держит весь файл в памяти:
Чтение = Новый ЧтениеТекста(ИмяФайла, КодировкаТекста.UTF8);
Строка = Чтение.ПрочитатьСтроку();
Пока Строка <> Неопределено Цикл
// разбор строки
Строка = Чтение.ПрочитатьСтроку();
КонецЦикла;
Чтение.Закрыть();
Код с ИмяФайла выполняется там, где лежит файл. Если пользователь выбирает файл у себя на компьютере, а разбор идёт на сервере, сначала передайте файл на сервер (НачатьПомещениеФайлаНаСервер или ПоместитьФайл), а на сервере получите двоичные данные из временного хранилища и работайте уже с ними.
Если на входе двоичные данные, а не путь, строку из них получают так:
Текст = ПолучитьСтрокуИзДвоичныхДанных(ДвоичныеДанные, "windows-1251");
Программное определение кодировки файла в 1С по байтам
Когда файлы приходят из разных источников и кодировка заранее неизвестна, её определяют кодом. Алгоритм в три шага:
- Проверить BOM. Метка однозначна:
EF BB BF(239, 187, 191) — UTF-8,FF FE(255, 254) — UTF-16LE,FE FF(254, 255) — UTF-16BE. - Проверить, корректный ли это UTF-8. У UTF-8 строгие правила: ведущий байт задаёт длину символа, а следующие байты обязаны лежать в диапазоне 128–191. Файл в Windows-1251 с кириллицей эту проверку практически никогда не проходит.
- Отличить Windows-1251 от CP866. В 1251 русские буквы занимают байты 192–255. В CP866 большая часть букв лежит в 128–175. Достаточно посчитать, каких байтов больше.
Буфер двоичных данных и обращение к байту по индексу доступны в платформе 8.3.9 и новее. Код ниже работает на сервере и на клиенте.
// Возвращает имя кодировки, которое можно передать в ТекстовыйДокумент.Прочитать()
Функция ОпределитьКодировкуФайла(ИмяФайла) Экспорт
ДД = Новый ДвоичныеДанные(ИмяФайла);
Буфер = ПолучитьБуферДвоичныхДанныхИзДвоичныхДанных(ДД);
Размер = Буфер.Размер;
// Шаг 1. Метка порядка байтов (BOM)
Если Размер >= 3 И Буфер[0] = 239 И Буфер[1] = 187 И Буфер[2] = 191 Тогда
Возврат "utf-8";
ИначеЕсли Размер >= 2 И Буфер[0] = 255 И Буфер[1] = 254 Тогда
Возврат "utf-16le";
ИначеЕсли Размер >= 2 И Буфер[0] = 254 И Буфер[1] = 255 Тогда
Возврат "utf-16be";
КонецЕсли;
// Анализируем не больше 64 КБ: для решения этого достаточно
Граница = Мин(Размер, 65536);
// Шаг 2. Корректный UTF-8 без BOM
Если ЭтоКорректныйUTF8(Буфер, Граница) Тогда
Возврат "utf-8"; // сюда же попадёт чистый ASCII - он совместим с UTF-8
КонецЕсли;
// Шаг 3. Windows-1251 или CP866
Байты1251 = 0;
Байты866 = 0;
Для Индекс = 0 По Граница - 1 Цикл
Байт = Буфер[Индекс];
Если Байт >= 192 Тогда
Байты1251 = Байты1251 + 1;
ИначеЕсли Байт >= 128 И Байт <= 175 Тогда
Байты866 = Байты866 + 1;
КонецЕсли;
КонецЦикла;
Если Байты866 > Байты1251 Тогда
Возврат "cp866";
КонецЕсли;
Возврат "windows-1251";
КонецФункции
Функция ЭтоКорректныйUTF8(Буфер, Граница)
Позиция = 0;
Пока Позиция < Граница Цикл
Байт = Буфер[Позиция];
Если Байт < 128 Тогда
Хвост = 0;
ИначеЕсли Байт >= 194 И Байт <= 223 Тогда
Хвост = 1;
ИначеЕсли Байт >= 224 И Байт <= 239 Тогда
Хвост = 2;
ИначеЕсли Байт >= 240 И Байт <= 244 Тогда
Хвост = 3;
Иначе
Возврат Ложь; // такой ведущий байт в UTF-8 невозможен
КонецЕсли;
Если Позиция + Хвост >= Граница Тогда
Прервать; // символ разрезан границей анализа - не считаем ошибкой
КонецЕсли;
Для Сч = 1 По Хвост Цикл
Следующий = Буфер[Позиция + Сч];
Если Следующий < 128 Или Следующий > 191 Тогда
Возврат Ложь;
КонецЕсли;
КонецЦикла;
Позиция = Позиция + Хвост + 1;
КонецЦикла;
Возврат Истина;
КонецФункции
Использование:
Кодировка = ОпределитьКодировкуФайла(ИмяФайла);
ТекстДок = Новый ТекстовыйДокумент;
ТекстДок.Прочитать(ИмяФайла, Кодировка);
Почему 64 КБ, а не весь файл. Цикл по байтам на встроенном языке медленный: на файле в десятки мегабайт он займёт заметное время. Первых 64 КБ хватает, чтобы встретить сотни русских букв и принять решение.
Ограничения метода, о которых нужно помнить:
- 🔸 Файл из одной латиницы и цифр определится как UTF-8. Это не ошибка: такие байты одинаковы во всех трёх кодировках.
- 🔸 KOI8-R алгоритм не распознаёт и вернёт
windows-1251. Если такие файлы реально приходят, добавьте отдельный счётчик или храните кодировку в настройках источника. - 🔸 Конструктор
Новый ДвоичныеДанные(ИмяФайла)читает файл целиком в память. Для файлов в сотни мегабайт читайте начало черезЧтениеДанных.
Конвертация текста: перекодировка из Windows-1251 в UTF-8 и обратно
Перекодировать файл в 1С можно без внешних утилит. Принцип один: прочитать байты в исходной кодировке в строку, а строку записать в нужной.
Через двоичные данные — с полным контролем над BOM:
ДД = Новый ДвоичныеДанные(ИмяИсходного);
Текст = ПолучитьСтрокуИзДвоичныхДанных(ДД, "windows-1251");
// Третий параметр - писать ли BOM. Ложь - файл без метки
ДДРезультат = ПолучитьДвоичныеДанныеИзСтроки(Текст, КодировкаТекста.UTF8, Ложь);
ДДРезультат.Записать(ИмяРезультата);
Через текстовый документ — короче, но с меньшим контролем:
ТекстДок = Новый ТекстовыйДокумент;
ТекстДок.Прочитать(ИмяИсходного, "cp866");
ТекстДок.Записать(ИмяРезультата, "windows-1251");
При записи в UTF-8 через ТекстовыйДокумент.Записать метка BOM, как правило, добавляется. Если получатель её не ждёт, проверьте первые байты результата или пишите через ПолучитьДвоичныеДанныеИзСтроки с явным Ложь.
Обратная перекодировка из UTF-8 в Windows-1251 может терять символы. Буквы казахского и украинского алфавитов частично, эмодзи, иероглифы, некоторые типографские знаки в 1251 отсутствуют. Они пропадут или превратятся в «?». Перед отправкой файла в систему, принимающую только 1251, просмотрите итог.
Если нужно перекодировать сотни файлов разом вне 1С, быстрее сделать это в консоли. В Linux: iconv -f WINDOWS-1251 -t UTF-8 in.csv > out.csv.
Диагностика проблем с файлами CSV и XML
CSV
CSV — самый частый источник жалоб, потому что формат не хранит кодировку нигде. Что важно знать о его происхождении:
- 📊 Excel при сохранении как «CSV (разделители — запятые)» пишет файл в Windows-1251, а разделителем на русской Windows ставит точку с запятой.
- 📊 Вариант «CSV UTF-8» в новых версиях Excel пишет UTF-8 с BOM.
- 🌐 Выгрузки сайтов, маркетплейсов и облачных сервисов почти всегда в UTF-8, часто без BOM.
Отсюда частая ловушка. Код ищет колонку по заголовку ИНН, а в файле с BOM первая строка начинается с невидимого символа U+FEFF. Сравнение «ИНН» = «ИНН» даёт Ложь, и загрузка пишет «колонка не найдена». Решение — удалить символ после чтения:
ПерваяСтрока = СтрЗаменить(ТекстДок.ПолучитьСтроку(1), Символ(65279), "");
Колонки = СтрРазделить(ПерваяСтрока, ";");
XML
С XML ситуация обратная: кодировка указана в самом файле, в декларации <?xml version="1.0" encoding="windows-1251"?>. ЧтениеXML ей доверяет. Если декларации нет, по стандарту XML файл считается UTF-8.
Проблемы начинаются, когда декларация не совпадает с реальными байтами. Например, файл выгрузили в 1251 и вручную пересохранили в UTF-8 текстовым редактором, а строку encoding не поправили. Парсер падает с ошибкой разбора или выдаёт мусор.
Порядок диагностики:
- Откройте файл в Notepad++ и сравните реальную кодировку со строкой
encoding. - Если отличаются — исправьте декларацию в источнике выгрузки. Это правильное решение.
- Если источник не исправить, прочитайте файл как текст в настоящей кодировке и передайте строку в
ЧтениеXML.УстановитьСтроку(). Байты к этому моменту уже раскодированы, и декларация не помешает.
При записи XML кодировку задают сразу: ЗаписьXML.ОткрытьФайл(ИмяФайла, "UTF-8"). Платформа пропишет её и в байтах, и в декларации.
Файл обмена с банком
Отдельный случай — текстовый файл обмена с клиент-банком в формате 1CClientBankExchange. В его заголовке есть строка Кодировка=Windows или Кодировка=DOS. Если выписка не загружается или назначения платежей нечитаемы, сравните эту строку с реальной кодировкой файла и с кодировкой в настройке обмена с банком на стороне 1С. Они должны совпадать.
Текстовый документ: вывод на экран и печать
Бывает, что файл прочитан, но проблема видна только при показе или печати. Здесь работает простое правило: кодировка исправляется при чтении, а не при выводе. Если текст уже попал в строку кракозябрами, никакая настройка шрифта или принтера его не вернёт.
Чтобы быстро показать пользователю содержимое файла, используйте:
ТекстДок = Новый ТекстовыйДокумент;
ТекстДок.Прочитать(ИмяФайла, ОпределитьКодировкуФайла(ИмяФайла));
ТекстДок.Показать("Содержимое файла");
Файл откроется во встроенном текстовом редакторе 1С, откуда его можно распечатать командой печати из главного меню.
Что учесть при выводе и печати:
- 🖨 Выравнивание колонок. Текстовые отчёты из старых программ выровнены пробелами. Для них нужен моноширинный шрифт, иначе таблица «поплывёт».
- 🖨 Псевдографика. Рамки из символов
┌─┐есть в CP866, но их нет в Windows-1251. Такой файл читайте только какcp866, иначе рамки превратятся в русские буквы. - 🖨 Печатная форма. Если текст нужно печатать регулярно и в аккуратном виде, выводите его не в текстовый, а в табличный документ: там управляются поля, шрифт и ориентация страницы.
- 🖨 Файл для оборудования. Некоторые кассовые и весовые программы принимают задания только в CP866. Записывайте их через
ТекстовыйДокумент.Записать(ИмяФайла, КодировкаТекста.OEM).