При разработке внешних обработок выгрузки проводок или остатков ТМЦ в Microsoft Excel разработчики часто сталкиваются с ситуацией, когда процедура успешно отрабатывает за один период, но при смене дат формирует пустой файл и выдает диалоговое окно: «Файл resume.xlw уже существует, заменить да/нет». Кроме того, выполнение часто прерывается ошибками Значение не является значением объектного типа (Наименование), а в операционной системе остаются висеть фоновые процессы EXCEL.EXE.
Разберем детально, почему возникают эти проблемы, как исправить логику формирования файла и запроса к регистрам бухгалтерии, а также рассмотрим более надежный способ сохранения данных без использования COM-объектов.
Проанализируем природу появления диалога о перезаписи resume.xlw. В объектной модели Microsoft Excel вызов метода Save() непосредственно у корневого COM-объекта приложения (например, Excel.Save()) трактуется как команда сохранения текущей рабочей области (Workspace). Файлом по умолчанию для такой рабочей области всегда выступает resume.xlw.
Чтобы исключить появление этого окна и корректно сохранить книгу с данными, необходимо вызывать метод сохранения у конкретного объекта книги (Workbook), указывая точный целевой путь к файлу:
// Неправильно: сохранение рабочей области Excel
Excel.Save();
// Правильно: сохранение конкретной рабочей книги
Книга.SaveAs(ПутьКФайлу);
// Либо через активную книгу
Excel.ActiveWorkbook.SaveAs(ПутьКФайлу);
Для подавления системных предупреждений Excel при перезаписи файла также следует временно отключить системные алерты свойством Excel.DisplayAlerts = 0 (или Ложь).
Выясним причину формирования пустого файла. Если при смене периода файл оказывается пустым, чаще всего обработка аварийно падает на первой же строке цикла выгрузки. Рассмотрим типичную ошибку:
{ВнешняяОбработка.Выгрузка.Форма(78)}: Значение не является значением объектного типа (Наименование)
Такое исключение возникает в момент обращения к реквизиту субконто, когда само субконто не заполнено (в выборку попадает значение NULL или Неопределено):
// Ошибка при отсутствии значения у субконто:
Лист.Cells(Строка, 19).Value = Выборка.СубконтоКт1.Наименование;
Если на счетах учета (например, 10, 41 или 08) по какой-либо проводке субконто не задано или субсчет имеет иную настройку субконто, цикл сразу прерывается, документ не успевает заполниться, а выгрузка завершается сбоем.
Для устранения этой проблемы применим два правила:
ЕСТЬNULL, чтобы в результат выборки всегда возвращалась строка, даже если субконто отсутствует:
ВЫБРАТЬ
ЕСТЬNULL(ХозрасчетныйДвиженияССубконто.СубконтоКт1.Наименование, "") КАК СубконтоКт1Наименование
ИЗ
РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(&НачалоПериода, &КонецПериода, ...)
ЗначениеЗаполнено():
Если ЗначениеЗаполнено(Выборка.СубконтоКт1) Тогда
Лист.Cells(Строка, 19).Value = Выборка.СубконтоКт1.Наименование;
Иначе
Лист.Cells(Строка, 19).Value = "";
КонецЕсли;
КонецДня() при передаче параметра в запрос, чтобы движения за последний день не отсекались:
Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ДатаНачала));
Запрос.УстановитьПараметр("КонецПериода", КонецДня(ДатаОкончания));
Когда выгрузка падает с ошибкой, приложение EXCEL.EXE остается в памяти операционной системы в фоновом режиме. При повторных запусках эти процессы накапливаются, блокируют файлы на диске и приводят к непредсказуемым сбоям при записи.
Посмотрим на пример безопасной работы с COM-объектом с использованием блока Попытка ... Исключение:
Попытка
Excel = Новый COMОбъект("Excel.Application");
Excel.DisplayAlerts = Ложь;
Книга = Excel.Workbooks.Add();
Лист = Книга.Sheets(1);
// Заполнение ячеек данными из выборки
// ...
// Корректное сохранение книги
Книга.SaveAs(ПутьКФайлу);
Книга.Close(Ложь);
Excel.Quit();
Исключение
// В случае ошибки гарантированно освобождаем ресурсы
Если Excel <> Неопределено Тогда
Excel.DisplayAlerts = Ложь;
Excel.Quit();
КонецЕсли;
ВызватьИсключение;
КонецПопытки;
Excel = Неопределено;
Обращение к ячейкам Excel через COM-соединение (OLE) имеет ряд существенных недостатков: медленная построчная запись, необходимость установленного MS Office, зависимость от разрядности платформы (32-bit / 64-bit) и невозможность стабильной работы на сервере 1С под Linux.
Наиболее надежным и быстрым стандартом платформы 1С является формирование отчета через ТабличныйДокумент с последующим прямым сохранением в формат XLSX.
Разберем по шагам, как реализовать этот подход:
ТабличныйДокумент с использованием областей макета или программного заполнения ячеек.Записать(), передавая перечисление ТипФайлаТабличногоДокумента.XLSX:
ТабДок = Новый ТабличныйДокумент;
// Заполняем ТабДок данными отчета (через макет или напрямую)
// ...
// Сохраняем в файл XLSX штатными средствами платформы
ТабДок.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.XLSX);
Такой способ исключает любые ошибки с файлом resume.xlw, в десятки раз ускоряет выгрузку больших объемов информации и не оставляет зависших процессов в операционной системе.