Чтение файла Excel из кода 1С: COM, табличный документ, ADO и XML
Содержание
Для разовой загрузки на клиенте хватает COM-соединения с Excel: три строки кода, читается любой формат. Для серверной загрузки и больших файлов берут ТабличныйДокумент или разбор XLSX как XML: они не требуют установленного Excel. Остальное решают объём файла, место запуска кода и то, нужно ли разбирать форматирование.
Загрузить данные из Excel
в 1С программно можно четырьмя путями: через COM-объект Excel.Application, через встроенный ТабличныйДокумент, через ADO (драйвер OLE DB) и распаковкой XLSX как ZIP-архива с XML. Ниже у каждого способа рабочий код, ограничения и случаи, когда он проигрывает остальным.
Какой способ выбрать под вашу задачу
Сначала ответьте на три вопроса: где выполняется код (клиент, сервер, фоновое задание), стоит ли на этой машине Excel и сколько строк в файле. Дальше всё видно из таблицы.
| Способ | Нужен Excel на машине | Сервер | Скорость на 100 тыс. строк | Главный риск |
|---|---|---|---|---|
COM Excel.Application | да | почти всегда нет | низкая при чтении по ячейкам | зависший процесс Excel в памяти |
ТабличныйДокумент.Прочитать() | нет | да | средняя | лишний расход памяти на форматирование |
| ADO / OLE DB | нет, нужен драйвер | зависит от разрядности | высокая | драйвер другой разрядности, угадывание типов |
| XLSX как XML | нет | да | высокая | сами разбираем даты и общие строки |
ТабличныйДокумент. COM даёт доступ к любым возможностям Excel, ТабличныйДокумент проще и не зависит от установленного пакета.ТабличныйДокумент или разбор XML. На COM на сервере не рассчитывайте: Excel не рассчитан на запуск без пользователя, а на Linux-сервере его нет вообще.ТабличныйДокумент с ручным поиском строки заголовков. Запрос ADO по таким листам ведёт себя непредсказуемо.Чтение через COM-соединение с Excel
Способ самый наглядный: 1С запускает Excel как внешнее приложение и работает с ним, как макрос. Подходит для клиентской стороны на Windows, когда Excel уже установлен.
Excel = Новый COMОбъект("Excel.Application");
Excel.DisplayAlerts = Ложь;
Excel.Visible = Ложь;
Попытка
Книга = Excel.Workbooks.Open(ПутьКФайлу, 0, Истина);
Лист = Книга.Worksheets(1);
ПоследняяСтрока = Лист.UsedRange.Rows.Count;
Для НомерСтроки = 2 По ПоследняяСтрока Цикл
Артикул = СокрЛП(Лист.Cells(НомерСтроки, 1).Value);
Количество = Лист.Cells(НомерСтроки, 3).Value;
// дальше разбор и запись в 1С
КонецЦикла;
Книга.Close(Ложь);
Исключение
ТекстОшибки = ОписаниеОшибки();
КонецПопытки;
Excel.Quit();
Excel = Неопределено;
Что здесь важно:
- 🔒 Второй параметр
Openотвечает за обновление связей, третий включает режим «только чтение». Исходный файл при этом не блокируется для других. - 🧹
Excel.Quit()вызывайте всегда, в том числе после ошибки. Иначе в диспетчере задач останется процессEXCEL.EXE, и через десяток запусков машина начнёт тормозить. - 🐌 Построчное чтение
Cells(i, j).Value— это отдельный вызов внешнего объекта на каждую ячейку. На 50 тысяч строк по 10 колонок получится полмиллиона обращений.
Чтобы ускорить, читайте диапазон целиком одним вызовом и разбирайте массив уже в 1С:
Область = Лист.Range(Лист.Cells(2, 1), Лист.Cells(ПоследняяСтрока, 10));
Данные = Область.Value.Выгрузить();
Проверьте индексацию полученного массива на маленьком диапазоне 2×2, прежде чем писать цикл на весь файл. Нумерация элементов у выгруженного массива отличается от нумерации строк и колонок в Excel.
Если на компьютере несколько версий Office или Excel запущен под другим пользователем, Новый COMОбъект("Excel.Application") может упасть с ошибкой доступа или вернуть не тот экземпляр. Для серверных задач этот способ лучше не использовать вообще.
Табличный документ вместо COM
ТабличныйДокумент умеет читать файлы Excel сам, без установленного пакета. Для XLSX в актуальных релизах платформы 8.3 это штатная возможность, на сервере она работает так же, как на клиенте.
Таблица = Новый ТабличныйДокумент;
Таблица.Прочитать(ПутьКФайлу, СпособЧтенияЗначенийТабличногоДокумента.Значение);
Для НомерСтроки = 2 По Таблица.ВысотаТаблицы Цикл
Артикул = СокрЛП(Таблица.Область(НомерСтроки, 1, НомерСтроки, 1).Текст);
Количество = Таблица.Область(НомерСтроки, 3, НомерСтроки, 3).Значение;
КонецЦикла;
Режим Значение возвращает то, что лежит в ячейке: число как число, дату как дату. Режим Текст вернёт строку так, как её видит пользователь, со всеми пробелами-разделителями тысяч. Для чисел и дат берите значение, для артикулов и кодов — текст, иначе код 00123 превратится в 123.
Минус способа: форматирование и объединённые ячейки тоже попадают в память. Файл на 200 тысяч строк с цветной разметкой занимает заметно больше места, чем сами данные.
Чтение через ADO и драйвер OLE DB
Excel здесь работает как база данных: лист — это таблица, шапка — имена полей. Подключаетесь через ADODB.Connection и пишете обычный SQL-запрос.
Соединение = Новый COMОбъект("ADODB.Connection");
Соединение.Open("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + ПутьКФайлу
+ ";Extended Properties=""Excel 12.0 Xml;HDR=YES;IMEX=1""");
Набор = Новый COMОбъект("ADODB.Recordset");
Набор.Open("SELECT * FROM [Лист1$]", Соединение);
Пока Не Набор.EOF Цикл
Артикул = СокрЛП(Набор.Fields("Артикул").Value);
Набор.MoveNext();
КонецЦикла;
Набор.Close();
Соединение.Close();
Условия, без которых способ не заработает:
- Установлен драйвер Microsoft Access Database Engine (поставщик
Microsoft.ACE.OLEDB.12.0или новее). - Разрядность драйвера совпадает с разрядностью процесса 1С. 64-разрядный клиент не увидит 32-разрядный драйвер и наоборот.
- Первая строка листа — действительно шапка, а не пустая строка и не заголовок отчёта.
Параметр IMEX=1 заставляет драйвер читать смешанные колонки как текст. Без него колонка, где первые строки числовые, а дальше встречается текст, вернёт пустые значения на текстовых ячейках. Именно так «теряются» артикулы вроде А-125 в колонке с цифрами.
Разбор XLSX как XML без Excel
Файл XLSX — это ZIP-архив. Внутри лежат XML-файлы, и их можно прочитать штатными объектами 1С. Способ быстрый и работает на любом сервере, но разбор придётся написать самому.
Нужные части архива:
xl/sharedStrings.xml— таблица общих строк. Текст ячеек хранится здесь один раз, а на листе лишь индекс.xl/worksheets/sheet1.xml— данные первого листа.xl/workbook.xml— список листов и их имена.
Порядок работы:
- Распакуйте архив через
ЧтениеZipФайлаво временный каталог (ПолучитьИмяВременногоФайла()даёт путь, каталог создайте сами). - Прочитайте
sharedStrings.xmlчерезЧтениеXMLв массив строк. - Пройдите по элементам
cвsheet1.xml. У каждого есть адрес в атрибутеr(напримерB7), тип в атрибутеtи значение в дочернем элементеv. - Если
t="s", значение вv— индекс в массиве общих строк. Еслиt="str", это результат формулы-строки. Еслиt="inlineStr", текст лежит прямо в ячейке. Еслиtнет, это число.
Пока Чтение.Прочитать() Цикл
Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента И Чтение.Имя = "c" Тогда
Адрес = Чтение.ЗначениеАтрибута("r");
ТипЯчейки = Чтение.ЗначениеАтрибута("t");
КонецЕсли;
КонецЦикла;
Даты в таких файлах лежат числом: количество дней от 30.12.1899. Преобразуйте так: Дата(1899, 12, 30) + Целое(Значение) * 86400. Дробная часть числа — время суток.
Пустые ячейки в XML часто просто отсутствуют, поэтому колонку определяйте по адресу из атрибута r, а не по порядковому номеру элемента в строке. Иначе после первой пропущенной ячейки данные поедут влево.
Когда COM не стартует: проверка соединения
Самая частая жалоба на COM — «Ошибка при вызове конструктора (COMObject)». Прежде чем менять код, проверьте среду.
&НаСервере и &НаКлиенте меняют машину.DisplayAlerts = Ложь и проверьте, что файл не открыт у другого пользователя.Quit() при ошибке. Откройте диспетчер задач, завершите лишние EXCEL.EXE и добавьте Quit() в блок обработки исключений.Extended Properties либо драйвер не той разрядности. Сверьте версию формата (Excel 12.0 Xml для XLSX) и разрядность.Ошибки данных и проверка перед записью
Проблемы с самим файлом встречаются чаще, чем проблемы с кодом. Прежде чем создавать документы, прогоните прочитанные строки через проверку и соберите все замечания в одну таблицу.
Проверяйте по очереди:
- 🔢 Числа в виде текста. В ячейке
1 250,50с неразрывным пробелом. Уберите пробелы (в том числе символ с кодом 160) и замените запятую на точку передЧисло(). - 📅 Даты. Одни ячейки хранят настоящую дату, другие текст «05.10.26». Обрабатывайте оба варианта и не пропускайте тихо те, что не распознались.
- 🔗 Ссылки на справочники. Артикул из файла ищите запросом сразу по пакету, а не по одному элементу в цикле. Ненайденное складывайте в отчёт об ошибках.
- 🚫 Пустые обязательные поля. Строку без количества или цены не загружайте и не обнуляйте молча.
- 🔁 Дубли. Одна позиция в двух строках должна либо складываться, либо попадать в отчёт.
Загружайте в два прохода. Первый читает файл и проверяет, ничего не записывая. Второй пишет данные, только если нет критичных замечаний. Пользователь получает полный список проблем сразу, а не по одной за запуск.
Перед загрузкой в рабочую базу проверьте код на копии и сделайте резервную копию. Программная загрузка может создать тысячи документов за секунды, и откатить их вручную долго.
Как ускорить загрузку больших файлов
Скорость почти никогда не упирается в чтение файла. Основное время съедает запись в базу и поиск связанных объектов.
Что даёт реальный выигрыш:
- Прочитать всё в таблицу значений, потом работать с ней. Чтение и запись не должны чередоваться ячейка за ячейкой.
- Один запрос вместо тысячи. Передайте артикулы временной таблицей и получите соответствие «артикул → ссылка» за один проход. Поиск
НайтиПоКоду()в цикле на 100 тысяч строк заметно медленнее. - Записывать порциями. Например, по 1000 строк в одной транзакции:
НачатьТранзакцию()иЗафиксироватьТранзакцию()на порцию, а не на всю загрузку и не на каждую строку. - Не обновлять форму на каждой строке. Индикатор прогресса показывайте раз в сотню или тысячу строк.
- Вынести загрузку в фоновое задание, если файл большой. Пользователь продолжит работу, а ошибку не потеряет: итог пишется в журнал.
- Для регистров сведений использовать набор записей. Заполнили набор целиком и записали одним вызовом, это быстрее, чем создавать запись по одной.
Ориентиры по времени очень зависят от сервера и объёма базы, поэтому измеряйте на своих данных: замерьте время чтения, проверки и записи отдельно. Часто выясняется, что чтение занимает секунды, а запись минуты.
Частые вопросы
Можно ли читать Excel в 1С без установленного Excel?
ТабличныйДокумент.Прочитать(), ADO с драйвером Access Database Engine и разбор XLSX как XML не требуют самого Excel.Почему нельзя вызвать COM-объект Excel в регламентном задании?
Что делать с файлами в старом формате XLS?
Excel 8.0 вместо Excel 12.0 Xml. Разбор через XML к XLS неприменим: это не ZIP-архив.Как узнать список листов книги?
Книга.Worksheets, у каждого листа есть свойство Name. При разборе XML имена листов лежат в xl/workbook.xml.