При работе с системой маркировки «Честный знак» (ГИС МТ) программисты часто сталкиваются с ситуацией, когда файл, сформированный программно, отклоняется системой без видимых причин. При этом визуально и даже при побайтовом сравнении файл кажется идентичным тому, что создан вручную в текстовом редакторе. В этой статье мы разберем основные причины такого поведения, начиная от самых тривиальных и заканчивая глубокими техническими нюансами работы платформы 1С с файловой системой и кодировками.
Разберем ситуацию, которая стала решением в обсуждаемой теме. Несмотря на то, что для операционной системы Windows регистр символов в расширении файла зачастую не имеет значения, веб-сервисы и загрузчики систем мониторинга могут быть построены на базе Linux-стека, где регистр критичен. Проанализируем, как это влияет на загрузку: если система ожидает строго расширение в нижнем регистре .csv, то файл с расширением .CSV может быть проигнорирован или распознан как файл неизвестного типа.
Практический совет: При программном формировании имени файла в 1С всегда принудительно приводите расширение к нижнему регистру. Рассмотрим пример кода:
ИмяФайла = "upload_codes_" + Формат(ТекущаяДата(), "ДФ=yyyyMMdd");
ПолноеИмя = ПутьККаталогу + ИмяФайла + ".csv"; // Используем нижний регистр
// Или через функцию НРег, если расширение приходит из настроек
Расширение = ".CSV";
ПолноеИмя = ПутьККаталогу + ИмяФайла + НРег(Расширение);
Одной из самых коварных проблем при создании текстовых файлов в 1С является автоматическое добавление метки BOM. При использовании кодировки КодировкаТекста.UTF8 платформа 1С добавляет в самое начало файла три байта (EF BB BF). Многие системы обработки данных, включая компоненты ГИС МТ, могут не ожидать этих байтов и воспринимать их как мусор в начале первой строки, что делает первый код маркировки в файле нечитаемым.
Выясним причину, почему обычные программы сравнения их не видят: большинство текстовых редакторов (и даже некоторые простые HEX-утилиты) скрывают BOM, считая его служебной информацией. Чтобы создать «чистый» файл без BOM в 1С, рекомендуется использовать кодировку "CESU-8" или записывать данные через двоичный поток. Рассмотрим, как это сделать правильно:
// Способ 1: Использование кодировки CESU-8 (записывает UTF-8 без BOM)
ЗаписьТекста = Новый ЗаписьТекста(ПолноеИмя, "CESU-8");
ЗаписьТекста.ЗаписатьСтроку(ДанныеКодаМаркировки);
ЗаписьТекста.Закрыть();
// Способ 2: Использование объекта ПотокВПамяти для полного контроля
ДанныеСтрокой = "200415404461";
Поток = Новый ПотокВПамяти();
ЗаписьДанных = Новый ЗаписьДанных(Поток, КодировкаТекста.UTF8, ПорядокБайтов.BigEndian, Ложь); // Ложь - не писать BOM
ЗаписьДанных.ЗаписатьСтроку(ДанныеСтрокой);
ЗаписьДанных.Закрыть();
ДвоичныеДанные = Поток.ЗакрытьИПолучитьДвоичныеДанные();
ДвоичныеДанные.Записать(ПолноеИмя);
Проанализируем структуру переноса строк. В разных операционных системах используются разные стандарты: в Windows это пара символов CR (возврат каретки) + LF (перевод строки), в Linux — только LF. Система «Честный знак» чаще всего ожидает стандарт Windows. При использовании метода ДобавитьСтроку() в объекте ТекстовыйДокумент, 1С может использовать системный разделитель, который зависит от среды выполнения (сервер на Linux или клиент на Windows).
Чтобы гарантировать корректность, разберем способ принудительной установки разделителя:
Текст = Новый ТекстовыйДокумент;
Текст.ДобавитьСтроку("Код1");
Текст.ДобавитьСтроку("Код2");
// Принудительно задаем разделитель строк перед записью
Текст.Записать(ПолноеИмя, КодировкаТекста.UTF8, Символы.ВК + Символы.ПС);
Если вы копируете текст из других источников, убедитесь, что в нем нет «квадратиков» или лишних символов ПС, которые могут вставляться платформой 1С при определенных манипуляциях со строками. Посмотрите на пример очистки строки перед записью:
ЧистаяСтрока = СтрЗаменить(ИсходнаяСтрока, Символы.ПС, "");
ЧистаяСтрока = СтрЗаменить(ЧистаяСтрока, Символы.ВК, "");
// Теперь записываем строку с нужным нам разделителем
Коды маркировки DataMatrix содержат специальный непечатный символ GS (Group Separator), имеющий код ASCII 29. При программной сборке кода (склеивании GTIN, серийного номера и «криптохвоста») этот символ часто теряется или заменяется на пробел. Визуально в блокноте файл будет выглядеть правильно, но валидатор «Честного знака» его не примет.
Разберем, как правильно вставить этот символ в строку 1С:
СимволGS = Символ(29);
КодДляЗаписи = "01" + GTIN + "21" + СерийныйНомер + СимволGS + "91" + Ключ + СимволGS + "92" + Подпись;
Важно помнить, что если вы открываете такой файл в обычном блокноте и пересохраняете его, блокнот может «вырезать» непечатные символы или заменить их, что делает файл работоспособным (если система ГИС МТ допускает отсутствие GS в определенных типах документов) или, наоборот, окончательно его портит.
Иногда проблема заключается не в содержимом файла, а в его доступности для веб-браузера в момент загрузки. Если в коде 1С объект ЗаписьТекста или Файл не был закрыт явно (через Закрыть()), операционная система может удерживать блокировку на чтение. В этом случае файл может отображаться в папке, но при попытке загрузить его на сайт система выдаст ошибку доступа или «пустой» контент.
Алгоритм проверки прав и блокировок:
Попытка...Исключение при работе с файлами.Записать() вызывается метод Закрыть().Если ваш файл по-прежнему не загружается, выполните следующие действия:
.csv.EF BB BF.0D 0A (CRLF).Символ(29), если он предусмотрен форматом кода.Использование этих методов позволит вам создавать полностью совместимые файлы для системы «Честный знак», избегая «загадочных» ситуаций, когда программный код выдает внешне правильный, но фактически невалидный результат.