При переходе с использования устаревших технологий (например, COM-соединения с Excel или ADO) на нативные средства платформы 1С:Предприятие, программисты часто сталкиваются с неожиданными ошибками. Одна из самых распространенных — "Формат файла не поддерживается" при вызове метода Прочитать() объекта ТабличныйДокумент. Ситуация выглядит парадоксально: файл корректно открывается в Microsoft Excel или LibreOffice, но 1С отказывается с ним работать.
В этой статье мы подробно разберем, почему возникает эта ошибка, проанализируем нюансы работы платформы 8.3.11 и выше, а также выясним, как правильно организовать чтение файлов на стороне сервера. Для быстрого построения алгоритма можно использовать шаблон обработки загрузки из Excel.
Рассмотрим типичный код, который часто используется во внешних обработках для загрузки данных. Процесс обычно делится на передачу файла с клиента на сервер и его последующее чтение:
&НаСервере
Функция ЗагрузитьНаСервере(АдресФайлаОбменаВХранилище)
// Генерируем путь во временном каталоге
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xls");
// Извлекаем двоичные данные из хранилища
ДанныеФайла = ПолучитьИзВременногоХранилища(АдресФайлаОбменаВХранилище);
// Записываем данные на диск сервера
ДанныеФайла.Записать(ИмяВременногоФайла);
// Пытаемся прочитать файл средствами 1С
ТабличныйДокумент = Новый ТабличныйДокумент;
ТабличныйДокумент.Прочитать(ИмяВременногоФайла, СпособЧтенияЗначенийТабличногоДокумента.Значение);
Возврат ТабличныйДокумент;
КонецФункции
На первый взгляд, код абсолютно корректен. Однако именно здесь кроется коварная особенность работы серверной части 1С и операционной системы. Как выяснилось в ходе обсуждения, основной причиной ошибки часто становится асинхронность или задержка дисковых операций. Операционная система (особенно в среде Windows) может удерживать файловый дескриптор после метода Записать() или использовать кэширование, из-за чего метод Прочитать() обращается к файлу, который еще фактически "не доехал" до диска или заблокирован процессом записи.
Если код выше работает исправно, но на определенных файлах все равно возникает ошибка формата, нам следует проанализировать структуру самого файла. Многие сторонние системы (банковские сервисы, CRM, веб-отчеты) используют "трюк": они генерируют обычную HTML-таблицу или XML-структуру (SpreadsheetML), но сохраняют файл с расширением .xls.
Разберем, почему это критично:
ТабличныйДокумент.Прочитать() работает строго. Если расширение указано как xls, он ожидает увидеть бинарный формат BIFF8 (стандарт Excel 97-2003).Рекомендация: откройте проблемный файл в обычном текстовом редакторе (Блокнот, Notepad++). Если вы видите теги <html> или <?xml ...>, значит, это не настоящий Excel-файл. В таком случае в методе Прочитать() нужно явно указывать ТипФайлаТабличногоДокумента.HTML.
Иногда автоматическое определение формата платформой дает сбой. Мы рекомендуем явно указывать тип файла в качестве третьего параметра метода Прочитать(). Это помогает платформе выбрать правильный алгоритм парсинга данных.
// Явное указание формата XLS (Excel 97-2003)
ТабличныйДокумент.Прочитать(ИмяВременногоФайла, СпособЧтенияЗначенийТабличногоДокумента.Значение, ТипФайлаТабличногоДокумента.XLS);
Если вы работаете с более современными файлами, используйте ТипФайлаТабличногоДокумента.XLSX. Это исключит лишние проверки платформы и ускорит процесс открытия. Для предварительной трансформации исходных документов подойдёт конвертер файлов из XLS в XLSX.
Проанализируем технический контекст версии 8.3.11. В этом релизе и последующем 8.3.12 в нативных библиотеках чтения файлов Excel были зафиксированы ошибки, связанные с обработкой сложных объектов внутри книги (макросы, диаграммы, сложные сводные таблицы). Если ТабличныйДокумент встречает элемент, который он не может отрисовать, он может выдать общую ошибку формата.
Также стоит учитывать разрядность сервера 1С:
.xls исторически ниже, чем в Windows-среде, из-за особенностей используемых библиотек трансляции.Если причина ошибки в том, что файл не успевает записаться на сервере, рассмотрим, как можно модернизировать наш код. Вместо того чтобы просто надеяться на скорость дисковой подсистемы, мы можем реализовать проверку существования и доступности файла.
Проанализируем пример "безопасного" чтения:
ДанныеФайла.Записать(ИмяВременногоФайла);
// Проверим, существует ли файл физически перед чтением
ФайлНаДиске = Новый Файл(ИмяВременногоФайла);
СчетчикПопыток = 0;
Пока Не ФайлНаДиске.Существует() И СчетчикПопыток < 10 Цикл
// Небольшая пауза, если файл еще не создался ОС
СчетчикПопыток = СчетчикПопыток + 1;
#Если Сервер Тогда
// На сервере можно использовать ожидание через заблокированные процессы,
// но проще дождаться появления файла в цикле
#КонецЕсли
КонецЦикла;
Если ФайлНаДиске.Существует() Тогда
ТабличныйДокумент.Прочитать(ИмяВременногоФайла);
Иначе
ВызватьИсключение "Не удалось зафиксировать файл на диске сервера";
КонецЕсли;
Выясним еще одну причину, которая часто ускользает от внимания программистов. Файлы, полученные из внешних источников (почта, интернет), могут помечаться операционной системой как небезопасные. В свойствах файла в NTFS появляется атрибут "Заблокировано" (Zone.Identifier). Хотя 1С работает от имени системного пользователя, на некоторых конфигурациях прав доступа это может блокировать чтение потоков данных файла. Если вы столкнулись с системной ошибкой при чтении, попробуйте предварительно "разблокировать" файл или копировать его данные в новый поток.
Не забывайте, что формат .xls (BIFF8) имеет жесткие ограничения:
Если файл был сформирован программно и эти лимиты были нарушены (например, записано 70 000 строк в формате XLS), Microsoft Excel может попытаться "починить" такой файл при открытии, а ТабличныйДокумент.Прочитать() просто выдаст ошибку формата, так как структура индексов внутри файла будет нарушена.
Для стабильной работы загрузки данных через ТабличныйДокумент придерживайтесь следующих правил:
ТипФайлаТабличногоДокумента в методе Прочитать().Записать()..xlsx, так как работа с ним в 1С реализована более стабильно и прозрачно.