Часто при разработке механизмов загрузки данных из Excel в 1С разработчики сталкиваются с ситуацией, когда код успешно обрабатывает современные файлы .xlsx, но полностью игнорирует или выдает ошибку при попытке прочитать старые файлы формата .xls. Давайте вместе разберем, почему это происходит и как построить универсальное решение.
Основное заблуждение кроется в понимании того, как работает метод ПолучитьИмяВременногоФайла(). Многие полагают, что указание расширения в параметрах этого метода как-то влияет на внутренние механизмы конвертации или распознавания формата файла. Это не так.
Метод ПолучитьИмяВременногоФайла() просто создает в операционной системе путь к файлу с заданным расширением. Если вы принудительно задаете ПолучитьИмяВременногоФайла("xlsx"), система создает пустой файл с расширением .xlsx. Если затем вы пытаетесь записать в него двоичные данные файла формата .xls, содержимое не меняется — внутри остается старый бинарный формат BIFF, а расширение у файла теперь «ложное». Когда 1С пытается прочитать такой файл методом ТабличныйДокумент.Прочитать(), она ожидает структуру XML (для формата .xlsx), но получает бинарные данные, что приводит к ошибке.
Чтобы избежать этой проблемы, необходимо передавать на сервер не просто двоичные данные, но и метаданные файла, в частности — его исходное расширение. На стороне клиента при использовании метода НачатьПомещениеФайлаНаСервер мы можем получить всю необходимую информацию об объекте.
Рассмотрим пример кода на клиенте:
&НаКлиенте
Процедура ЗагрузитьФайл(Команда)
ОкончаниеПомещения = Новый ОписаниеОповещения("ОбработчикОкончанияПомещения", ЭтотОбъект);
ПараметрыДиалога = Новый ПараметрыДиалогаПомещенияФайлов;
ПараметрыДиалога.Фильтр = "Excel файлы(*.xls;*.xlsx)|*.xls;*.xlsx";
НачатьПомещениеФайлаНаСервер(ОкончаниеПомещения,,, АдресВХ, ПараметрыДиалога, ЭтотОбъект.УникальныйИдентификатор);
КонецПроцедуры
&НаКлиенте
Процедура ОбработчикОкончанияПомещения(ОписаниеПомещенногоФайла, ДополнительныеПараметры) Экспорт
Если ОписаниеПомещенногоФайла <> Неопределено Тогда
АдресФайла = ОписаниеПомещенногоФайла.Адрес;
Расширение = ОписаниеПомещенногоФайла.СсылкаНаФайл.Расширение;
ПрочитатьДанныеНаСервере(АдресФайла, Расширение);
КонецЕсли;
КонецПроцедуры
Теперь, когда расширение корректно передано на сервер, мы не должны жестко прописывать «xlsx» в коде. Мы будем использовать динамическое значение, полученное от пользователя. Это позволит методу ПолучитьИмяВременногоФайла() создавать временный файл с тем же расширением, которое было у исходного документа.
Разберем пример серверной процедуры:
&НаСервере
Процедура ПрочитатьДанныеНаСервере(АдресВХ, Расширение)
// Генерируем временный файл с оригинальным расширением
ИмяВременногоФайла = ПолучитьИмяВременногоФайла(Расширение);
ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресВХ);
ДвоичныеДанные.Записать(ИмяВременногоФайла);
ТабДок = Новый ТабличныйДокумент;
Попытка
ТабДок.Прочитать(ИмяВременногоФайла);
// Далее работаем с данными ТабличногоДокумента
Исключение
Сообщить("Ошибка при чтении файла: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
.csv или .ods), код не потребует изменений — он будет просто «подхватывать» нужное расширение.Попытка...Исключение, так как мы точно знаем, какой файл собираемся открывать.Мы проанализировали ситуацию и выяснили, что ключ к успеху — это сохранение метаданных файла при передаче в хранилище. Используя ОписаниеПомещенногоФайла.СсылкаНаФайл.Расширение, вы обеспечиваете стабильную работу механизма импорта независимо от версии Excel, в которой был сохранен документ. Теперь вы можете смело применять этот подход в своих разработках!