Как исправить чтение украинских символов из XML-файла в кодировке windows-1251 на мобильном устройстве в 1С?

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

Разработка мобильных приложений на платформе 1С:Предприятие часто преподносит неприятные сюрпризы, связанные с кроссплатформенностью. Один из таких классических багов — некорректная обработка национальных символов (например, украинских букв «і», «ї», «є») при чтении XML-файлов в устаревшей однобайтовой кодировке windows-1251. Настольная версия программы может отображать все данные корректно, однако при запуске того же кода на мобильном клиенте или в мобильном приложении (под управлением Android или iOS) вместо нужных букв начинают появляться другие символы.

В этой статье мы подробно разберем, почему возникает эта проблема, проанализируем внутренние механизмы платформы и рассмотрим несколько эффективных способов ее решения: от простого пересохранения файла на диске до оптимизированного декодирования «на лету» в оперативной памяти мобильного устройства.

Выясняем причину: почему символ «і» превращается в «ґ»?

Для начала давайте разберем физическую суть проблемы. В стандартной кодовой таблице windows-1251 байтовые коды некоторых украинских букв расположены вплотную друг к другу:

Мобильные операционные системы изначально спроектированы для работы исключительно с многобайтовой кодировкой UTF-8. Поддержка устаревших региональных однобайтовых кодировок (таких как windows-1251) в мобильных ОС реализуется через сторонние библиотеки трансляции (например, ICU — International Components for Unicode). При чтении файла через объект ЧтениеXML мобильная платформа 1С пытается сопоставить байты источника с таблицей символов Юникода. Из-за внутренней ошибки смещения или некорректной реализации декодера в мобильной платформе байт 0xB3 ошибочно интерпретируется как соседний 0xB4. В результате в строковые переменные 1С вместо буквы «і» записывается буква «ґ».

Примечательно, что если прочитать этот же файл обычным текстовым парсером ЧтениеТекста с явным указанием кодировки, декодирование на мобильном устройстве отрабатывает без ошибок. Это связано с тем, что механизмы чтения XML и обычного текста используют разные программные модули ядра платформы.


Решение 1. Чтение файла как текста с последующим пересохранением в UTF-8

Самый очевидный способ, к которому пришел автор темы на форуме, — это предварительное текстовое чтение «проблемного» файла, исправление заголовка XML с указанием новой кодировки и перезапись файла на диск в формате UTF-8.

Давайте подробно разберем этот алгоритм по шагам:

  1. Мы открываем файл с помощью объекта ЧтениеТекста, явно указав кодировку "windows-1251". В этом режиме мобильная платформа корректно преобразует байты в строку Юникода.
  2. Считываем все содержимое файла в строковую переменную.
  3. Поскольку мы планируем сохранить файл в кодировке UTF-8, нам обязательно нужно скорректировать заголовок XML (декларацию), заменив строку encoding="windows-1251" на encoding="UTF-8". Если этого не сделать, парсер ЧтениеXML выдаст ошибку несоответствия реальной кодировки заявленной.
  4. Записываем полученную строку обратно на диск, используя объект ЗаписьТекста с кодировкой "UTF-8".
  5. После этого мы можем стандартно открывать файл через ЧтениеXML — все украинские символы распознаются корректно.

Посмотрим на пример реализации данного метода в виде функции:


&НаСервереБезКонтекста
Функция ПересохранитьИПрочитатьФайл(ПутьКФайлу)
    
    // Шаг 1: Читаем исходный файл в правильной кодировке windows-1251
    ТекстовыйЧтец = Новый ЧтениеТекста(ПутьКФайлу, "windows-1251");
    СодержимоеФайла = ТекстовыйЧтец.Прочитать();
    ТекстовыйЧтец.Закрыть();
    
    // Шаг 2: Корректируем декларацию XML-документа
    СодержимоеФайла = СтрЗаменить(СодержимоеФайла, "windows-1251", "UTF-8");
    СодержимоеФайла = СтрЗаменить(СодержимоеФайла, "WINDOWS-1251", "UTF-8");
    
    // Шаг 3: Перезаписываем файл на диск в кодировке UTF-8
    ТекстовыйПисатель = Новый ЗаписьТекста(ПутьКФайлу, КодировкаТекста.UTF8);
    ТекстовыйПисатель.Записать(СодержимоеФайла);
    ТекстовыйПисатель.Закрыть();
    
    // Шаг 4: Теперь файл готов к корректному разбору парсером XML
    Парсер = Новый ЧтениеXML;
    Парсер.ОткрытьФайл(ПутьКФайлу);
    
    Пока Парсер.Прочитать() Цикл
        // Здесь выполняется стандартная обработка узлов XML
        Если Парсер.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
            Наименование = Парсер.ЗначениеАтрибута("Naimenovanie");
            // Теперь украинские символы (включая "і") отображаются корректно!
        КонецЕсли;
    КонецЦикла;
    Парсер.Закрыть();

КонецФункции

Данный подход полностью решает проблему, однако имеет существенный недостаток: выполнение лишних операций записи на диск мобильного устройства. На мобильных телефонах и планшетах дисковые операции ввода-вывода (I/O) являются крайне медленными, а частая перезапись файлов приводит к преждевременному износу флеш-памяти.


Решение 2. Оптимизированный метод без перезаписи файла (Двоичные данные)

Чтобы избежать медленных дисковых операций, мы можем выполнить перекодирование файла прямо в оперативной памяти мобильного устройства. Для этого воспользуемся возможностями работы с двоичными данными, которые появились в платформе 1С 8.3.

Проанализируем этот изящный метод по шагам:

  1. Мы считываем исходный XML-файл с диска в виде объекта ДвоичныеДанные. Эта операция выполняется очень быстро, так как платформа просто считывает поток байтов без их анализа и декодирования.
  2. Используем метод платформы ПолучитьСтрокуИзДвоичныхДанных(), передавая туда наш объект двоичных данных и явно указывая кодировку "windows-1251". Системные декодеры этого метода работают гораздо стабильнее, чем внутренний транслятор объекта ЧтениеXML, поэтому на выходе мы получаем абсолютно чистую и корректную строку Юникода без искажения украинских букв.
  3. Для инициализации разбора XML мы используем метод УстановитьСтроку() объекта ЧтениеXML вместо метода ОткрытьФайл(). Это позволяет передать готовую строку напрямую парсеру без промежуточного сохранения на флеш-накопитель устройства.

Рассмотрим пример кода, реализующий этот высокопроизводительный вариант:


&НаКлиентеИлиНаСервере
Процедура БыстроеЧтениеXMLБезПерезаписи(ПутьКФайлу)

    // Шаг 1: Загружаем файл как массив байтов
    ФайлДвоичныеДанные = Новый ДвоичныеДанные(ПутьКФайлу);
    
    // Шаг 2: Преобразуем байты в строку с корректным декодированием windows-1251
    СтрокаXML = ПолучитьСтрокуИзДвоичныхДанных(ФайлДвоичныеДанные, "windows-1251");
    
    // Шаг 3: Загружаем декодированную строку в парсер XML
    Парсер = Новый ЧтениеXML;
    Парсер.УстановитьСтроку(СтрокаXML);
    
    // Шаг 4: Читаем данные XML из оперативной памяти
    Пока Парсер.Прочитать() Цикл
        Если Парсер.ТипУзла = ТипУзлаXML.НачалоЭлемента И Парсер.Имя = "Товар" Тогда
            Наименование = Парсер.ЗначениеАтрибута("Naimenovanie");
            // Все символы отображаются корректно, дисковые операции минимизированы!
        КонецЕсли;
    КонецЦикла;
    Парсер.Закрыть();

КонецПроцедуры

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


Важные особенности работы объекта ЧтениеXML

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


Глобальная рекомендация для разработчиков мобильных приложений

Несмотря на то, что приведенные выше костыли и обходные пути гарантированно решают проблему «здесь и сейчас», стандарт разработки мобильных приложений 1С настоятельно рекомендует полностью исключить передачу файлов в однобайтовых кодировках (таких как windows-1251, IBM866, ISO-8859-5) на мобильные устройства.

При проектировании любых механизмов интеграции, мобильных обменов, выгрузок данных из учетных систем (будь то XML, JSON или простые текстовые файлы) всегда используйте кодировку UTF-8 (желательно без метки BOM). Переход на UTF-8 является единственным стандартом, который гарантирует абсолютно идентичное отображение любых национальных алфавитов и спецсимволов на любых операционных системах — Windows, Linux, macOS, Android и iOS — без необходимости написания сложных процедур перекодирования.

← На главную