При программной обработке табличных документов часто возникает необходимость заблокировать исходный файл от одновременного редактирования пользователем. Если файл открывается в фоновом режиме через COMОбъект("Excel.Application"), разработчик ожидает, что при попытке интерактивного открытия Excel выведет стандартное предупреждение о занятости файла другим процессом. Однако на практике интерактивный Excel нередко открывает такой файл без предупреждений, что приводит к ошибкам при сохранении или чтении данных в 1С.
Разберем причины такого поведения, изучим методы управления режимом доступа через COM и рассмотрим надежные альтернативные способы контроля блокировок средствами платформы 1С.
Проанализируем технические причины, из-за которых при фоновом открытии через COM файл не блокируется должным образом:
Excel.Application инициализируется с параметром Visible = Ложь, он может не зарегистрировать открытую книгу в глобальной таблице активных объектов Windows. Интерактивный экземпляр Excel при запуске не находит информацию о занятости файла и пытается открыть его заново.~$ИмяФайла.xlsx в той же директории. Если фоновый процесс или пользователь не имеют полных прав на создание временных файлов в каталоге, файл блокировки не формируется.Посмотрим на пример инициализации COM-объекта и попытку явного переключения прав доступа с помощью метода ChangeFileAccess объекта книги.
// Инициализация COM-объекта Excel
Приложение = Новый COMОбъект("Excel.Application");
Приложение.Visible = Ложь;
Приложение.DisplayAlerts = Ложь;
ПутьКФайлу = "C:\Files\Реестр.xlsx";
Книга = Приложение.WorkBooks.Open(ПутьКФайлу);
// Проверяем статус открытия и пытаемся установить режим записи
Если Книга.ReadOnly Тогда
// xlReadWrite = 2, Notify = Истина (в COM передается -1 или True)
Mode = 2;
Notify = Истина;
Попытка
Книга.ChangeFileAccess(Mode, , Notify);
Исключение
Сообщить("Не удалось заблокировать файл на запись: " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
Приложение.DisplayAlerts = Истина;
Параметр DisplayAlerts временно отключает системные диалоги, чтобы выполнение кода 1С не зависало на модальных окнах Excel. Однако отключение предупреждений в момент открытия может подавлять и штатные механизмы регистрации блокировок, поэтому включать DisplayAlerts = Истина следует сразу после настройки режима доступа.
Поскольку поведение COM-объекта Excel сильно зависит от установленной версии офисного пакета и разрядности операционной системы, полагаться исключительно на методы OLE небезопасно. Разберем практический способ проверки доступности файла средствами встроенного языка 1С перед обращением к тяжелым внешним объектам.
Попробуем выполнить монопольный захват файла на уровне операционной системы:
Функция ФайлЗаблокирован(Знач ПолноеИмяФайла)
Файл = Новый Файл(ПолноеИмяФайла);
Если Не Файл.Существует() Тогда
Возврат Ложь;
КонецЕсли;
// Проверяем наличие временного файла блокировки Excel
ИмяФайлаБлокировки = Файл.Путь + "~$" + Файл.Имя;
ФайлБлокировки = Новый Файл(ИмяФайлаБлокировки);
Если ФайлБлокировки.Существует() Тогда
Возврат Истина;
КонецЕсли;
// Пробуем кратковременно переименовать файл для проверки файлового дескриптора
ВременноеИмя = Файл.Путь + "test_lock_" + Файл.Имя;
Попытка
ПереместитьФайл(ПолноеИмяФайла, ВременноеИмя);
ПереместитьФайл(ВременноеИмя, ПолноеИмяФайла);
Возврат Ложь;
Исключение
// Если файл занят любым процессом, ОС выбросит исключение
Возврат Истина;
КонецПопытки;
КонецФункции
Рассмотрим порядок применения этой проверки:
WorkBooks.Open вызываем функцию ФайлЗаблокирован().Истина, выводим пользователю понятное сообщение и прерываем операцию, не создавая висящих процессов в диспетчере задач.Если цель фоновой обработки — исключительно чтение данных без необходимости длительного удержания исходного файла, оптимальным решением является копирование книги во временную директорию сеанса.
КаталогВременный = КаталогВременныхФайлов();
ИмяВременногоФайла = КаталогВременный + "temp_" + НомерВерсии + ".xlsx";
КопироватьФайл(ПутьКИсходномуФайлу, ИмяВременногоФайла);
// Работаем с изолированной копией через COM
Приложение = Новый COMОбъект("Excel.Application");
Приложение.Visible = Ложь;
Книга = Приложение.WorkBooks.Open(ИмяВременногоФайла);
// Чтение данных...
Книга.Close(Ложь);
Приложение.Quit();
Приложение = Неопределено;
УдалитьФайлы(ИмяВременногоФайла);
Такой подход полностью исключает конфликты между пользователем и кодом 1С: пользователь может свободно вносить правки в рабочий документ, пока 1С считывает данные из снимка.
Выделим главное ограничение COM-автоматизации: зависимость от разрядности клиента, нестабильность фоновых процессов EXCEL.EXE при аварийных завершениях и несовместимость с серверами на базе Linux. Для чтения и формирования файлов Excel в платформе 1С предусмотрен встроенный объект ТабличныйДокумент.
Посмотрим, как считать файл без использования внешних библиотек:
ТабДок = Новый ТабличныйДокумент;
Попытка
ТабДок.Прочитать(ПутьКФайлу);
// Обработка строк и колонок через ТабДок.ПолучитьОбласть()
Исключение
Сообщить("Не удалось прочитать файл: " + ОписаниеОшибки());
КонецПопытки;
Метод Прочитать() объекта ТабличныйДокумент открывает файл на чтение, быстро извлекает данные и сразу освобождает дескриптор, предотвращая конфликты блокировок.