При работе с файлами Microsoft Excel на стороне сервера в среде 1С:Предприятие 8.3 программисты часто сталкиваются с неочевидной ошибкой: «Ошибка при выполнении операции... Доступ к файлу не может быть получен». Эта проблема может сбивать с толку, так как она часто проявляется избирательно — например, файлы .mxl открываются без проблем, а современные форматы .xlsx вызывают сбой. Проанализируем причины этой ситуации и разберем пошагово методы её решения.
Рассмотрим ситуацию, представленную в обсуждении. Программист передает файл с клиента на сервер через временное хранилище, а затем сохраняет его на диск сервера, используя метод ПолучитьИмяВременногоФайла("xls"). Именно здесь кроется критическая ошибка. Проанализируем, как работает метод ТабличныйДокумент.Прочитать(). Платформа 1С использует расширение файла в качестве подсказки для выбора внутреннего алгоритма (парсера), который будет обрабатывать структуру данных.
Если мы сохраняем файл формата OpenXML (xlsx) с расширением .xls, система пытается прочитать его как старый бинарный формат BIFF8 (Excel 97-2003). В результате несоответствия внутренней структуры и ожидаемого формата платформа выдает ошибку доступа. Это происходит потому, что чтение прерывается на низком уровне, и операционная система или сама платформа интерпретирует это как невозможность корректно захватить дескриптор файла.
Чтобы решить эту проблему, нам необходимо динамически определять расширение исходного файла и передавать его в функцию создания временного имени. Рассмотрим исправленный вариант логики:
// На стороне клиента получаем расширение
лстр_ПолноеИмяФайла = ИмяФайла; // Путь, выбранный пользователем
ТекФайл = Новый Файл(лстр_ПолноеИмяФайла);
лстр_Расширение = ТекФайл.Расширение; // Например, ".xlsx"
// Передаем файл и расширение на сервер
ДвоичныеДанные = Новый ДвоичныеДанные(лстр_ПолноеИмяФайла);
Адрес = ПоместитьВоВременноеХранилище(ДвоичныеДанные);
Результат = ПрочитатьФайлНаСервере(Адрес, лстр_Расширение);
Теперь на сервере мы должны использовать это расширение (убрав точку, если необходимо), чтобы временный файл соответствовал оригиналу:
&НаСервере
Функция ПрочитатьФайлНаСервере(Адрес, лстр_Расширение)
// Убираем точку из расширения для метода ПолучитьИмяВременногоФайла
ЧистоеРасширение = СтрЗаменить(лстр_Расширение, ".", "");
лстр_ИмяФайла = ПолучитьИмяВременногоФайла(ЧистоеРасширение);
ДанныеХранилища = ПолучитьИзВременногоХранилища(Адрес);
ДанныеХранилища.Записать(лстр_ИмяФайла);
ТабДок = Новый ТабличныйДокумент;
Попытка
ТабДок.Прочитать(лстр_ИмяФайла);
Исключение
ЗаписьЖурналаРегистрации("ЧтениеФайла", УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
// Важно: всегда удаляйте временные файлы после использования!
УдалитьФайлы(лстр_ИмяФайла);
Возврат ТабДок;
КонецФункции
Проанализируем структуру кода дальше. Часто разработчики разделяют процесс на «сохранение» и «чтение», опасаясь, что файл не успеет «освободиться» после записи. Однако в 1С:Предприятие 8.3 операции выполняются последовательно. Более того, на современных версиях платформы (начиная с 8.3.10) можно полностью избежать записи файла на диск сервера, что решает проблемы с правами доступа к папке Temp.
Выясним причину, почему работа через поток лучше: метод ТабличныйДокумент.Прочитать() может принимать в качестве параметра поток (объект ЧтениеДанных). Это позволяет обрабатывать файл целиком в оперативной памяти.
Рассмотрим пример реализации без создания временного файла на диске:
&НаСервере
Функция ПрочитатьФайлВПамяти(АдресХранилища)
ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресХранилища);
// Создаем поток из двоичных данных
Поток = ДвоичныеДанные.ОткрытьПотокДляЧтения();
ТабДок = Новый ТабличныйДокумент;
Попытка
// Платформа сама определит тип данных внутри потока
ТабДок.Прочитать(Поток);
Исключение
Сообщить("Ошибка чтения: " + ОписаниеОшибки());
КонецПопытки;
Поток.Закрыть();
Возврат ТабДок;
КонецФункции
Если расширение указано верно, но ошибка «Доступ к файлу не может быть получен» сохраняется, нам необходимо проверить системные настройки сервера. Служба «1C:Enterprise 8.3 Server Agent» запускается от имени определенного пользователя (обычно USR1CV8 в Windows или usr1cv8 в Linux).
Проанализируем следующие моменты:
ПолучитьИмяВременногоФайла(). В Windows это обычно C:\Windows\Temp или профиль пользователя службы AppData\Local\Temp.Записать(), антивирус может мгновенно захватить файл для проверки, и в этот же миг метод Прочитать() получает отказ в доступе. Рекомендуется добавить временные папки 1С в исключения антивируса..tmp файлов (более 65 тысяч). В таком случае создание нового файла может завершиться ошибкой доступа. Периодическая очистка Temp — обязанность системного администратора.Если ваш сервер 1С работает под управлением Linux, следует учитывать специфику этой ОС. Разберем важные нюансы:
.XLSX и .xlsx — это разные сущности. Убедитесь, что ваш код не меняет регистр расширения непредсказуемым образом.libgsf, fontconfig и freetype. Без них парсинг сложных табличных документов может завершаться аварийно с общей ошибкой доступа.Выясним причину еще одного типа сбоев. Файлы, сформированные в старых системах (например, 1С:Предприятие 7.7) или сторонним ПО, могут иметь расширение .xls, но фактически являться HTML-документами или очень старыми бинарными форматами (Excel 2.1).
Современный ТабличныйДокумент в версии 8.3 может отказаться читать такие файлы через стандартный метод Прочитать(). Если вы столкнулись с сообщением «Формат файла не поддерживается», единственным надежным способом будет предварительное открытие такого файла в MS Excel и его пересохранение в формат Excel 2007+ (xlsx). На серверах под управлением Windows это можно автоматизировать через COM-объект Excel.Application, но помните, что это требует установленного Microsoft Office на сервере и настройки прав в DCOMCNFG.
Подводя итог, можно сказать, что в 90% случаев ошибка доступа к Excel-файлу на сервере решается простым контролем соответствия расширения временного файла исходному расширению загружаемого документа. Использование потоков (ЧтениеДанных) является более современным и надежным методом, который мы рекомендуем внедрять во все новые разработки.