Как исправить некорректную кодировку (абракадабру) при чтении XML-файла в 1С

Программист 1С v8.3 (Управляемые формы) Бухгалтерский учет IT и автоматизация бизнеса
← На главную

При разработке механизмов обмена данными, особенно при загрузке банковских выписок или электронных чеков, программисты часто сталкиваются с ситуацией, когда вместо понятного русского текста в информационную базу попадает странный набор символов — так называемая «абракадабра» (модзибакэ). Рассмотрим типичный пример: 711Рќ6394001;0100008)РГК. На первый взгляд это кажется нечитаемым набором байтов, но для опытного разработчика это четкий сигнал о проблеме интерпретации кодировок.

В данной статье мы подробно разберем, почему возникает такая ситуация, проанализируем механизмы работы платформы 1С с кодировками и реализуем надежное решение, которое позволит вашей обработке корректно читать файлы в любом формате.

Выясняем причину возникновения «абракадабры»

Давайте проанализируем ситуацию. Текст вида Рќ вместо русских букв — это классический признак того, что файл, сохраненный в кодировке UTF-8, пытаются прочитать как Windows-1251 (стандартная кириллическая кодировка в Windows). В UTF-8 каждый символ кириллицы кодируется двумя байтами, и первый байт большинства русских букв (с кодом D0 или D1) в однобайтовой кодировке Windows-1251 отображается как буквы «Р» или «С».

Проблема часто кроется в том, что объект ЧтениеXML не всегда может автоматически определить кодировку файла, если в самом начале XML-документа отсутствует заголовок (декларация) вида <?xml version="1.0" encoding="UTF-8"?>. Если этого тега нет или он содержит неверную информацию, 1С может попытаться прочитать файл в системной кодировке по умолчанию, что и приводит к искажению данных.

Почему стандартные свойства ЧтениеXML не помогают?

Многие начинающие разработчики пытаются использовать свойства ЧтениеXML.КодировкаXML или ЧтениеXML.КодировкаИсточника, надеясь «заставить» объект сменить кодировку на лету. Однако, если мы обратимся к документации, то увидим, что эти свойства доступны только для чтения. Они показывают результат того, как 1С уже распознала файл, но не позволяют программно изменить этот выбор после открытия файла.

Метод ОткрытьФайл() у объекта ЧтениеXML также не имеет параметра для явного указания кодировки. Поэтому нам необходимо подготовить данные заранее, прежде чем передавать их в парсер XML.

Решение проблемы через предварительное чтение в строку

Рассмотрим наиболее эффективный способ, предложенный в обсуждении. Суть метода заключается в том, чтобы сначала прочитать содержимое файла как обычный текст с явным указанием кодировки КодировкаТекста.UTF8, а затем передать полученную строку в объект ЧтениеXML.

Разберем по шагам реализацию функции, которая получает данные из временного хранилища и подготавливает их для парсинга:


&НаСервере
Функция ЧтениеXMLИзДвоичныхДанных(АдресДвоичныхДанных)
    // Создаем путь для временного файла на сервере
    ВременныйФайл = ПолучитьИмяВременногоФайла("xml");
    
    // Извлекаем двоичные данные из хранилища (куда они попали после выбора файла пользователем)
    ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресДвоичныхДанных);
    
    // Записываем данные во временный файл для последующего текстового чтения
    ДвоичныеДанные.Записать(ВременныйФайл);
    
    // Используем объект ЧтениеТекста, где мы МОЖЕМ явно указать кодировку UTF8
    ЧтениеТекста = Новый ЧтениеТекста;
    ЧтениеТекста.Открыть(ВременныйФайл, КодировкаТекста.UTF8);
    
    // Читаем весь файл целиком в одну строковую переменную
    СодержимоеФайла = ЧтениеТекста.Прочитать();
    ЧтениеТекста.Закрыть();
    
    // Удаляем временный файл, так как данные уже в памяти
    УдалитьФайлы(ВременныйФайл);
    
    // Инициализируем ЧтениеXML и загружаем в него готовую строку
    ЧтениеXML = Новый ЧтениеXML;
    ЧтениеXML.УстановитьСтроку(СодержимоеФайла);
    
    Возврат ЧтениеXML;
КонецФункции

После этого мы можем работать с объектом ЧтениеXML привычным способом, используя цикл Пока ЧтениеXML.Прочитать(). Поскольку мы передали в него уже «расшифрованную» строку, проблема с кодировкой исчезнет. Для разбора полученных XML-данных и их конвертации в структуру 1С удобно использовать готовую функцию чтения XML в структуру.

Оптимизация: работа с большими файлами через потоки

Метод с чтением всего файла в строку через ЧтениеТекста.Прочитать() прост и надежен, но у него есть существенный минус: если файл банковской выписки будет очень большим (десятки или сотни мегабайт), оперативная память сервера может переполниться. В современных версиях платформы 1С (начиная с 8.3.10) реализована поддержка потоков, которая позволяет решить задачу более элегантно.

Проанализируем, как можно использовать ЧтениеТекста в качестве обертки напрямую, не загружая весь текст в память:


&НаСервере
Процедура ПрочитатьXMLЧерезПоток(АдресДвоичныхДанных)
    ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресДвоичныхДанных);
    
    // Получаем поток из двоичных данных
    Поток = ДвоичныеДанные.ОткрытьПотокДляЧтения();
    
    // Создаем чтение текста на основе потока с указанием кодировки
    ЧтениеТекста = Новый ЧтениеТекста(Поток, КодировкаТекста.UTF8);
    
    // Инициализируем ЧтениеXML
    ЧтениеXML = Новый ЧтениеXML;
    
    // Открываем ЧтениеXML, передавая в него объект ЧтениеТекста
    // Платформа будет сама подтягивать данные из потока частями
    ЧтениеXML.ОткрытьФайл(ЧтениеТекста);
    
    Пока ЧтениеXML.Прочитать() Цикл
        // Обработка узлов XML
        Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
            Если ЧтениеXML.Имя = "PayPurpose" Тогда
                // Здесь текст будет уже в правильной кодировке
                НазначениеПлатежа = ЧтениеXML.ПрочитатьСодержимоеКакСтроку();
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
    
    ЧтениеXML.Закрыть();
    ЧтениеТекста.Закрыть();
    Поток.Закрыть();
КонецПроцедуры

Этот способ является наиболее профессиональным, так как он сочетает в себе и корректную обработку кодировок, и бережное отношение к ресурсам сервера.

Важные рекомендации при работе с XML и кодировками

Для того чтобы в будущем минимизировать ошибки при обмене данными, придерживайтесь следующих правил:

  1. Проверяйте наличие BOM: Иногда файлы в формате UTF-8 содержат специальную метку (Byte Order Mark) в самом начале. 1С обычно хорошо распознает файлы с BOM, но если метки нет, используйте методы, описанные выше.
  2. Используйте явное указание кодировки при записи: Если вы сами формируете XML для банка, всегда используйте объект ЗаписьXML и метод УстановитьСтроку() или ОткрытьФайл() с указанием кодировки, чтобы на стороне получателя не возникало аналогичных проблем.
  3. Обработка спецсимволов: Помните, что в значениях XML (например, в назначении платежа) не должно быть запрещенных символов типа & или < без экранирования. Объект ЧтениеXML выдаст ошибку, если встретит их. Если файл сформирован некорректно, вам придется сначала «почистить» строку методами СтрЗаменить().
  4. Тестирование на разных ОС: Если ваша база работает на Linux-сервере, помните, что системные кодировки по умолчанию там отличаются от Windows, поэтому явное указание КодировкаТекста.UTF8 становится обязательным условием стабильной работы.

Подводя итог, можно сказать, что «абракадабра» в 1С — это не приговор и не ошибка в данных, а лишь неверно выбранный «декодер». Использование объекта ЧтениеТекста в связке с ЧтениеXML позволяет полностью контролировать процесс преобразования байтов в понятные пользователю символы. Кроме того, при разработке надежных механизмов обмена полезно задействовать обработку для проверки валидности XML-файла на соответствие схеме XSD.

← На главную