При работе с платформой 1С:Предприятие 8.3 (особенно на релизах линейки 8.3.13, включая 8.3.13.1644) разработчики часто сталкиваются с неприятным багом: при импорте файлов формата XLSX встроенными средствами платформы кириллические символы превращаются в нечитаемые символы («кракозябры»). Это явление очень напоминает старые проблемы с несовместимостью кодировок (ANSI, OEM, UTF-8).
В этой статье мы подробно разберем, почему возникает этот сбой, заглянем «под капот» формата Office Open XML и рассмотрим четыре практических способа решения этой проблемы — от простых обходных путей до полноценного программного парсинга.
Для того чтобы понять природу бага, проанализируем внутреннюю структуру файла .xlsx. На самом деле этот файл представляет собой обычный ZIP-архив, содержащий набор XML-документов. Текстовое содержимое ячеек и стили оформления хранятся раздельно:
/xl/sharedStrings.xml в кодировке UTF-8./xl/styles.xml.Когда вы создаете документ в Microsoft Excel и используете шрифт по умолчанию (например, стандартный Arial или Calibri), Excel оптимизирует структуру XML. Он не прописывает явно кодовую страницу кириллицы для стандартного шрифта. В файле styles.xml описание шрифта выглядит максимально лаконично:
<font>
<name val="Arial"/>
</font>
Обратите внимание: здесь отсутствует параметр charset, указывающий на конкретный языковой стандарт (для кириллицы в кодировке Windows-1251 это значение должно быть равным 204).
Встроенный парсер платформы 1С 8.3.13 при выполнении метода ТабличныйДокумент.Прочитать() анализирует стили ячеек. Не обнаружив явного указания набора символов (charset) для шрифта Arial, парсер ошибочно принимает кодовую страницу по умолчанию за западноевропейскую (CP1252 / Latin-1) или некорректно декодирует байты UTF-8 из файла sharedStrings.xml. В результате русские буквы превращаются в двухбайтную «абракадабру» (например, «РњР°СЃС‚РµС...»).
Если же мы принудительно меняем шрифт в Excel (например, на Calibri, Times New Roman или Arial Cyr) или делаем начертание полужирным, Excel создает новый стиль в styles.xml и принудительно прописывает тег <charset val="204"/>:
<font>
<name val="Arial"/>
<charset val="204"/>
</font>
Обнаружив этот тег, парсер 1С корректно переключается на обработку кириллицы, и текст импортируется без искажений.
---
Если файлы генерируются вручную или у вас есть возможность повлиять на бизнес-процесс подготовки файлов, самым простым решением будет изменение шрифта по умолчанию в исходном файле Excel.
Рассмотрим по шагам, как это сделать:
---
Если файлы загружаются в автоматическом режиме и вы не можете контролировать их создание, ручное пересохранение не подойдет. В сценариях, когда сервер 1С работает под управлением операционной системы Windows, мы можем использовать COM-объект Microsoft Excel для программного чтения данных.
Посмотрим на пример кода, который реализует такое чтение:
Функция ПрочитатьExcelЧерезCOM(ПутьКФайлу) Экспорт
Попытка
ExcelПриложение = Новый COMОбъект("Excel.Application");
Исключение
ЗаписатьЛогСобытий("Не удалось запустить MS Excel на сервере: " + ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
// Отключаем предупреждения и видимость окна для ускорения работы
ExcelПриложение.Visible = Ложь;
ExcelПриложение.DisplayAlerts = Ложь;
Попытка
Книга = ExcelПриложение.Workbooks.Open(ПутьКФайлу);
Лист = Книга.Sheets(1); // Читаем первый лист
// Получаем используемый диапазон ячеек
Диапазон = Лист.UsedRange;
ВсегоСтрок = Диапазон.Rows.Count;
ВсегоКолонок = Диапазон.Columns.Count;
ТаблицаДанных = Новый ТаблицаЗначений;
Для НомерКолонки = 1 По ВсегоКолонок Цикл
ТаблицаДанных.Колонки.Add("Колонка_" + НомерКолонки);
КонецЦикла;
Для НомерСтроки = 1 По ВсегоСтрок Цикл
НоваяСтрока = ТаблицаДанных.Добавить();
Для НомерКолонки = 1 По ВсегоКолонок Цикл
ЗначениеЯчейки = Лист.Cells(НомерСтроки, НомерКолонки).Value;
НоваяСтрока[НомерКолонки - 1] = ЗначениеЯчейки;
КонецЦикла;
КонецЦикла;
Книга.Close(Ложь);
ExcelПриложение.Quit();
Возврат ТаблицаДанных;
Исключение
ExcelПриложение.Quit();
ВызватьИсключение "Ошибка при чтении данных из Excel: " + ОписаниеОшибки();
КонецПопытки;
КонецФункции
Преимущества: Данный метод полностью решает проблему кодировок, так как декодированием данных занимается сам движок Microsoft Office.
Ограничения: Способ работает медленно на файлах объемом более 10 000 строк и абсолютно не подходит для серверов 1С, работающих под управлением Linux.
---
Для высоконагруженных систем и Linux-серверов идеальным решением является ручная распаковка структуры XLSX и прямое чтение XML-файлов. Этот подход полностью независим от наличия MS Office в системе и работает в десятки раз быстрее, чем COM.
Проанализируем базовый алгоритм распаковки и чтения словаря строк:
Функция ПолучитьТаблицуСтрокXLSX(ПутьКФайлу, КаталогРаспаковки)
// Распаковываем XLSX как ZIP-архив
Архив = Новый ЧтениеZipФайла(ПутьКФайлу);
Архив.ИзвлечьВсе(КаталогРаспаковки, РежимВосстановленияПутейФайлов.Восстанавливать);
Архив.Закрыть();
ФайлСловаря = КаталогРаспаковки + "/xl/sharedStrings.xml";
МассивСтрок = Новый Массив;
Если ФС_Существует(ФайлСловаря) Тогда
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ФайлСловаря);
Пока ЧтениеXML.Прочитать() Цикл
Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента И ЧтениеXML.Имя = "t" Тогда
// Читаем строковое значение из тега <t>
ТекстСтроки = ЧтениеXML.ПрочитатьСтроку();
МассивСтрок.Добавить(ТекстСтроки);
КонецЕсли;
КонецЦикла;
ЧтениеXML.Закрыть();
КонецЕсли;
Возврат МассивСтрок;
КонецФункции
После получения массива уникальных строк мы можем прочитать файл разметки листа /xl/worksheets/sheet1.xml, где сопоставить индексы ячеек со значениями из нашего массива. Поскольку чтение XML-файлов платформой 1С всегда выполняется строго в UTF-8, данный способ полностью застрахован от сбоев кодировки Arial.
---
Если баг проявляется локально на клиентских компьютерах пользователей под управлением ОС Windows, проблему со шрифтом Arial можно решить на уровне операционной системы, настроив подмену кодовых страниц.
Разберем по шагам системную настройку через реестр:
regedit и нажмите Enter для открытия Редактора реестра.HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutesArial,0.Arial,204.Данная настройка сообщает операционной системе, что при запросе шрифта Arial с дефолтным набором символов (charset 0) необходимо использовать кириллическое представление (charset 204). Это исправит ошибку рендеринга и распознавания текста встроенным парсером 1С.
---
Описанный баг парсера файлов Office Open XML официально признан ошибкой платформы «1С:Предприятие». Фирма «1С» устранила этот дефект в последующих версиях платформы.
Если вы столкнулись с этой проблемой на релизе 8.3.13.1644, наиболее надежным и стратегически верным решением будет обновление платформы 1С до актуальных минорных версий (ошибка исправлена в ветках 8.3.14, 8.3.15 и во всех последующих стабильных версиях).
После обновления платформы метод ТабличныйДокумент.Прочитать() начнет корректно определять UTF-8 строки в XLSX-документах независимо от того, какие параметры кодовых таблиц прописаны для шрифта по умолчанию.