При интеграции терминалов сбора данных (ТСД) с системой 1С программисты часто сталкиваются с ситуацией, когда выгруженный файл выглядит «битым»: между каждой буквой стоят пробелы, а часть текста превращается в нечитаемые иероглифы. Попытка открыть такой файл стандартным объектом ЧтениеXML приводит к ошибке, а обычная замена пробелов через СтрЗаменить не дает результата.
В данной статье мы подробно разберем, почему возникает эта проблема, проанализируем внутреннюю структуру такого файла и научимся исправлять её программно средствами 1С.
Проанализируем ситуацию: визуальные «пробелы» между символами — это не настоящие пробелы (код 32), а нулевые байты (null-bytes, 0x00). Это происходит из-за того, что устройство записывает данные в кодировке UTF-16LE. В этой кодировке каждый символ занимает ровно два байта. Для стандартных латинских символов и цифр первый байт содержит код символа, а второй — нулевой. Если открыть такой файл в редакторе, который ожидает однобайтовую кодировку (например, Windows-1251 или UTF-8), эти нулевые байты будут отображаться как пустоты или спецсимволы.
Однако главная проблема даже не в этом. Рассмотрим, почему файл «ломается» посередине:
CRLF как однобайтовый (0x0D 0x0A вместо правильных для UTF-16 0x0D 0x00 0x0A 0x00).encoding="UTF-8", хотя фактически данные лежат в UTF-16, что окончательно сбивает с толку парсер 1С.Поскольку файл поврежден на уровне байтов, мы не можем работать с ним как с текстом. Нам необходимо прочитать его как ДвоичныеДанные, найти некорректные последовательности и заменить их. Рассмотрим алгоритм исправления «сдвига» байтов.
Проанализируем пример кода, который восстанавливает структуру UTF-16LE, корректируя символы переноса строк:
Функция ИсправитьБитыйФайлТСД(ПутьКФайлу)
// Читаем файл в двоичном виде
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлу);
Буфер = ОбластьДанных(ДвоичныеДанныеФайла); // Получаем доступ к байтам
// Создаем новый буфер для исправленных данных
НовыйБуфер = Новый БуферДвоичныхДанных(Буфер.Размер * 1.5);
СчетчикНового = 0;
Для Индекс = 0 По Буфер.Размер - 1 Цикл
Байт = Буфер[Индекс];
// Проверяем на наличие последовательности 0D 0A (перенос строки)
Если Байт = 13 И (Индекс + 1 < Буфер.Размер) И Буфер[Индекс + 1] = 10 Тогда
// Если нашли короткий перенос, превращаем его в правильный UTF-16LE
НовыйБуфер[СчетчикНового] = 13;
НовыйБуфер[СчетчикНового + 1] = 0;
НовыйБуфер[СчетчикНового + 2] = 10;
НовыйБуфер[СчетчикНового + 3] = 0;
СчетчикНового = СчетчикНового + 4;
Индекс = Индекс + 1; // Пропускаем обработанный 0A
Иначе
НовыйБуфер[СчетчикНового] = Байт;
СчетчикНового = СчетчикНового + 1;
КонецЕсли;
КонецЦикла;
// Отрезаем лишнее от буфера и сохраняем
ИтоговыеДанные = НовыйБуфер.ПрочитатьДвоичныеДанные(0, СчетчикНового);
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xml");
ИтоговыеДанные.Записать(ИмяВременногоФайла);
Возврат ИмяВременногоФайла;
КонецФункции
Важный момент: если файл начинается с BOM (Byte Order Mark) для UTF-8 (EF BB BF), а данные внутри — UTF-16, 1С не сможет его прочитать. В этом случае в начале файла нужно заменить эти три байта на FF FE (маркер UTF-16LE).
Если «сдвига» байтов нет, а проблема только в лишних нулевых символах (например, весь файл — честный UTF-16, но без BOM), мы можем попробовать прочитать его, принудительно указав кодировку UTF-16. Рассмотрим, как это сделать правильно:
Текст = Новый ЧтениеТекста;
// Указываем кодировку UTF-16 явно
Текст.Открыть(ПутьКФайлу, "UTF-16");
Содержимое = Текст.Прочитать();
Текст.Закрыть();
// Теперь заменяем ошибочный заголовок, если он мешает парсеру
Содержимое = СтрЗаменить(Содержимое, "encoding=""UTF-8""", "encoding=""UTF-16""");
// Записываем исправленный текст обратно в UTF-8 для стандартного ЧтениеXML
ТекстЗаписи = Новый ЗаписьТекста(ПутьКФайлуИсправленный, КодировкаТекста.UTF8);
ТекстЗаписи.Записать(Содержимое);
ТекстЗаписи.Закрыть();
Этот метод сработает только в том случае, если ТСД не допустил ошибку «смещения» при записи переносов строк. Если же иероглифы появляются именно после первой строки — используйте Способ 1.
Проанализируем содержимое атрибута BarCodeBase64 из примера. Даже если сам XML выглядит странно, данные внутри часто упакованы в Base64. После того как вы восстановили структуру XML и смогли прочитать узлы, вам потребуется декодировать значения.
В 1С для этого используется объект Base64Значение. Посмотрим на пример обработки строки из файла:
// Пример значения из атрибута: "MjA4MTA0NzU3ODUxNA=="
ЗначениеBase64 = "MjA4MTA0NzU3ODUxNA==";
ДвоичныеДанныеШтрихкода = Base64Значение(ЗначениеBase64);
ШтрихкодТекст = ПолучитьСтрокуИзДвоичныхДанных(ДвоичныеДанныеШтрихкода, КодировкаТекста.UTF8);
// Результат: "2081047578514"
Чтобы не заниматься «лечением» файлов в 1С, рекомендуется проверить настройки самого ТСД и его программного обеспечения:
UTF-8. Это избавит от появления нулевых байтов.Используя предложенные методы бинарной коррекции, вы сможете стабильно загружать данные в 1С даже из «проблемных» устройств, обеспечивая корректный учет товаров и оборудования.