При работе с внешними компонентами для 1С версии 7.7, такими как Йоксель (Yoksel), мы часто сталкиваемся с задачами интеграции табличных документов. Одна из распространенных проблем возникает, когда необходимо программно прочитать данные из файла Excel, который в данный момент открыт пользователем для редактирования. Давайте разберем эту ситуацию подробно, выясним технические причины ошибки доступа и рассмотрим надежные способы решения задачи.
Рассмотрим типичный сценарий: на складе используется файл Excel для учета адресного хранения («карта склада»). Кладовщики держат этот файл постоянно открытым, чтобы видеть актуальную информацию или вносить изменения. Наша задача — средствами 1С (используя Йоксель) периодически считывать данные из этого файла для сверки с базой или формирования отчетов.
При попытке открыть такой файл методом Йокселя ОткрытьФайл (или аналогичным методом загрузки), 1С выдает ошибку доступа или просто не загружает документ. Почему это происходит?
Давайте проанализируем механизм работы файловой системы и приложений:
EXCEL.EXE, операционная система отказывает компоненте Йоксель в доступе.Как справедливо замечено в технической документации и обсуждениях сообщества, идеология Йокселя подразумевает работу с файлами «как есть»: читаем монопольно, пишем монопольно. Йоксель не умеет «договариваться» с Excel о получении данных из оперативной памяти.
Самым надежным и стабильным решением, которое устраняет конфликт блокировок, является создание временной копии файла. Если нам не требуется синхронизация в реальном времени (до миллисекунды), а достаточно данных, актуальных на момент запуска обработки, мы можем скопировать занятый файл во временную директорию и прочитать уже эту копию.
Разберем алгоритм действий:
FileSystemObject.Посмотрим на пример реализации копирования файла средствами встроенного языка и Windows Script Host:
// Функция создает копию файла и возвращает путь к ней
Функция СоздатьВременнуюКопию(ПутьКФайлу)
ФСО = СоздатьОбъект("Scripting.FileSystemObject");
// Проверим, существует ли файл
Если ФСО.FileExists(ПутьКФайлу) = 0 Тогда
Сообщить("Исходный файл не найден: " + ПутьКФайлу);
Возврат "";
КонецЕсли;
// Формируем имя временного файла
ВременныйКаталог = КаталогВременныхФайлов(); // Или жестко заданный путь
ИмяФайла = ФСО.GetFileName(ПутьКФайлу);
Расширение = ФСО.GetExtensionName(ПутьКФайлу);
// Добавим уникальности имени, чтобы не пересекаться с другими копиями
ИмяВременногоФайла = ВременныйКаталог + "_" + _GetPerformanceCounter() + "." + Расширение;
Попытка
// Метод CopyFile: Откуда, Куда, Перезаписывать (1 - да)
// CopyFile работает на уровне ОС и обычно может скопировать даже открытый файл,
// если он не заблокирован "намертво" (что в Excel случается редко для чтения)
ФСО.CopyFile(ПутьКФайлу, ИмяВременногоФайла, 1);
Возврат ИмяВременногоФайла;
Исключение
Сообщить("Не удалось скопировать файл. Возможно, он заблокирован слишком строго.");
Возврат "";
КонецПопытки;
КонецФункции
// Пример использования с Йокселем
Процедура ПрочитатьДанные()
ИсходныйПуть = "C:\Sklad\Map.xls";
ПутьКопии = СоздатьВременнуюКопию(ИсходныйПуть);
Если ПустойСтроку(ПутьКопии) = 1 Тогда
Возврат;
КонецЕсли;
ТабДок = СоздатьОбъект("ТабличныйДокумент"); // Объект Йокселя (примерное имя класса)
Попытка
ТабДок.Открыть(ПутьКопии);
// ... Чтение данных из ячеек ...
Сообщить("Файл успешно прочитан из копии.");
Исключение
Сообщить("Ошибка при открытии копии файла Йокселем.");
КонецПопытки;
// Удаляем мусор за собой
ФСО = СоздатьОбъект("Scripting.FileSystemObject");
Если ФСО.FileExists(ПутьКопии) = 1 Тогда
Попытка
ФСО.DeleteFile(ПутьКопии);
Исключение
Сообщить("Не удалось удалить временный файл.");
КонецПопытки;
КонецЕсли;
КонецПроцедуры
Этот метод хорош тем, что он не мешает пользователю работать в Excel и гарантированно предоставляет Йокселю файл, к которому есть полный доступ.
Если копирование файла кажется избыточным (например, файл очень большой), или если мы хотим получить выборку данных быстрее, чем перебор ячеек, рассмотрим альтернативу — чтение через ADO (ActiveX Data Objects).
Драйверы OLE DB часто умеют читать данные из открытых книг Excel, если в строке подключения указать правильный режим. Это позволяет обращаться к листам Excel как к таблицам базы данных.
Посмотрим, как это реализуется:
Процедура ЧтениеЧерезADO(ПутьКФайлу)
Connection = СоздатьОбъект("ADODB.Connection");
RecordSet = СоздатьОбъект("ADODB.RecordSet");
// Строка подключения для xls (Jet OLEDB)
// Важный параметр: Mode=Read (или ReadOnly) и IMEX=1 (читать все как текст)
СтрокаПодключения = "Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data Source=" + ПутьКФайлу + ";" +
"Mode=Read;" +
"Extended Properties=""Excel 8.0;HDR=No;IMEX=1;""";
Попытка
Connection.Open(СтрокаПодключения);
Исключение
Сообщить("Не удалось подключиться к файлу Excel через ADO.");
Возврат;
КонецПопытки;
// Выполняем SQL запрос к первому листу
// Обратите внимание на синтаксис: [ИмяЛиста$]
ТекстЗапроса = "SELECT * FROM [Лист1$]";
RecordSet.Open(ТекстЗапроса, Connection);
Пока RecordSet.EOF() = 0 Цикл
// Читаем поля по индексу или имени (если HDR=Yes)
ЗначениеЯчейки = RecordSet.Fields(0).Value;
Сообщить(ЗначениеЯчейки);
RecordSet.MoveNext();
КонецЦикла;
RecordSet.Close();
Connection.Close();
КонецПроцедуры
Преимущества ADO: высокая скорость, возможность фильтрации WHERE прямо в запросе, часто игнорирует блокировку файла пользователем.
Недостатки: требует установленных драйверов в системе, сложнее работать с оформлением (цвета, рамки), только «чистые» данные.
Если ни Йоксель, ни ADO не подходят, и вам критически важно работать с объектной моделью Excel, можно использовать стандартный OLE-объект. Хотя это медленнее и тяжелее для системы, OLE позволяет открыть книгу в режиме «Только чтение», что игнорирует блокировку.
При вызове метода Open нужно передать соответствующие параметры:
Эксель = СоздатьОбъект("Excel.Application");
Эксель.DisplayAlerts = 0; // Отключаем вопросы пользователю
// Параметры Open:
// 1. FileName
// 2. UpdateLinks (0 - не обновлять)
// 3. ReadOnly (1 - Открыть только для чтения) <--- КЛЮЧЕВОЙ МОМЕНТ
Книга = Эксель.Workbooks.Open(ПутьКФайлу, 0, 1);
Лист = Книга.Worksheets(1);
Значение = Лист.Cells(1, 1).Value;
Книга.Close(0); // Закрываем без сохранения
Эксель.Quit();
В настройках Excel существует функция «Доступ к книге» (Share Workbook), позволяющая нескольким пользователям редактировать файл одновременно. Может показаться, что включение этого режима позволит Йокселю открыть файл.
Однако, давайте проанализируем риски:
Поэтому мы настоятельно не рекомендуем использовать режим Shared Workbook исключительно ради того, чтобы Йоксель мог прочитать файл.
Наконец, стоит рассмотреть проблему стратегически. Если файл Excel становится узким местом, где данные постоянно меняются и блокируются, это сигнал к тому, что данные «переросли» формат электронной таблицы.
В контексте 1С, правильным решением будет перенос данных адресного хранения внутрь базы данных 1С:
Это полностью снимет вопрос блокировок файлов и обеспечит целостность данных.