Как в 1С прочитать конкретный лист Excel с помощью табличного документа

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Чтение данных из файлов Microsoft Excel — одна из самых частых задач, в которых помогает универсальная загрузка из Excel — для этого есть универсальный импорт любых данных из Excel в документы и справочники 1С. Традиционно для этого использовались COM-объекты, хотя современный импорт данных из Excel работает быстрее и не требует наличия установленного Office на сервере. Более современным и кроссплатформенным способом является использование объекта ТабличныйДокумент. В этой статье мы подробно разберем, как прочитать не весь файл сразу, а только конкретный лист по его порядковому номеру, используя шаблон простой обработки загрузки из excel, и как избежать типичных ошибок с координатами ячеек.

Особенности механизма чтения Excel через ТабличныйДокумент

Прежде чем переходить к коду, проанализируем, как именно платформа 1С воспринимает файл Excel. В этом процессе может помочь портативная обработка чтения файла в таблицу — для этого подойдёт универсальный импорт данных из Excel в справочники 1С. Когда мы вызываем метод Прочитать() для объекта ТабличныйДокумент, система считывает всю книгу целиком. При этом все листы Excel выстраиваются один за другим по вертикали, образуя один «длинный» документ.

Важный технический момент: для каждого листа в результирующем табличном документе автоматически создается именованная область. Имя этой области совпадает с названием листа в Excel. Эти области хранятся в коллекции ТабДок.Области в том же порядке, в котором листы расположены в исходной книге. Это позволяет нам обращаться к листам по индексу, что критично, если пользователи могут переименовывать листы, но их порядок остается неизменным.

Валидация номера листа

Рассмотрим ситуацию, когда пользователь вводит номер листа на форме. Прежде чем приступать к обработке, необходимо убедиться, что введенное значение корректно. Выясним, как это реализовать правильно. Мы не можем просто попытаться прочитать лист, так как обращение к несуществующему индексу коллекции вызовет исключение.

Для проверки мы сначала читаем весь файл во временный объект, а затем проверяем количество элементов в коллекции Области:


// На сервере
ТабДокВесь = Новый ТабличныйДокумент;
ТабДокВесь.Прочитать(ПутьКФайлу);

КоличествоЛистов = ТабДокВесь.Области.Количество();

Если Объект.ЛистФайла < 1 Или Объект.ЛистФайла > КоличествоЛистов Тогда
    Сообщить("Ошибка. Неверно указан номер листа книги Excel. Всего листов: " + КоличествоЛистов);
    Возврат;
КонецЕсли;

Способ 1: Использование метода ВставитьОбласть

Посмотрим на пример из обсуждения, где предлагается выделить область конкретного листа и вставить ее в новый, «чистый» табличный документ. Это позволяет работать с данными одного листа изолированно.


&НаСервере
Функция ПолучитьФайлExcel(Адрес)
    ИмяФайлаExcel = ПолучитьИмяВременногоФайла("xlsx");
    ФайлExcel = ПолучитьИзВременногоХранилища(Адрес);
    ФайлExcel.Записать(ИмяФайлаExcel);
    
    ТабДок = Новый ТабличныйДокумент;
    Попытка
        ТабДок.Прочитать(ИмяФайлаExcel);
    Исключение
        Возврат Неопределено;
    КонецПопытки;

    ТабДокНовый = Новый ТабличныйДокумент;
    // Получаем область по индексу (отсчет от 0)
    НужнаяОбласть = ТабДок.Области.Получить(Объект.ЛистФайла - 1);
    ТабДокНовый.ВставитьОбласть(НужнаяОбласть);
    
    Возврат ТабДокНовый;
КонецФункции

Проблема смещения координат и «пустых» ячеек

Разберем ситуацию, с которой столкнулся автор темы: почему после выделения листа в новый документ данные (например, даты) перестают считываться или возвращают пустые строки? Проанализируем причину. Она кроется в абсолютных координатах.

Когда вы копируете область из середины большого документа в новый документ, её физические координаты меняются. В исходном документе лист №2 мог начинаться со строки 100. В коде обработки цикла часто используются переменные типа СтрокаФайла = Объект.ПерваяСтрока. Если ПерваяСтрока равна 2, то в новом документе (где остался только один лист) вы попадете во вторую строку этого листа. Но если вы используете старый табличный документ и просто «навелись» на область, вы должны учитывать смещение.

Решение: всегда используйте ПолучитьОбласть() с явным указанием координат границ листа. Это гарантирует, что в новом табличном документе данные начнутся с первой строки и первой колонки.

Способ 2: Оптимальное извлечение листа через координаты

Проанализируем более надежный метод. Мы находим границы области листа и создаем новый документ на основе этих координат:


&НаСервере
Функция ПолучитьЛистПоИндексу(ВесьТабДок, ИндексЛиста)
    // Получаем описание области листа
    ОбластьОригинал = ВесьТабДок.Области[ИндексЛиста];
    
    // Извлекаем чистые данные по координатам: Верх, Лево, Низ, Право
    ОбластьДанных = ВесьТабДок.ПолучитьОбласть(ОбластьОригинал.Верх, ОбластьОригинал.Лево, ОбластьОригинал.Низ, ОбластьОригинал.Право);
    
    ТабДокЛист = Новый ТабличныйДокумент;
    ТабДокЛист.Вывести(ОбластьДанных);
    
    Возврат ТабДокЛист;
КонецФункции

Этот метод хорош тем, что ТабДокЛист теперь содержит только данные одного листа, и индекс первой строки данных в нем всегда будет равен 1, независимо от того, каким по счету этот лист был в оригинальном файле.

Работа с форматами дат при чтении Excel

Часто ошибка Индекс находится за границами массива возникает при попытке разобрать дату методом СтрРазделить(ТекДата, "."). Если ячейка прочиталась как пустая строка или в другом формате (например, через дробь), массив разделителей будет иметь меньше элементов, чем ожидалось.

Рассмотрим, как сделать чтение даты более защищенным. Вместо прямой работы со строками, рекомендуется проверять содержимое ячейки:


ТекЯчейка = ТабДок.Область(СтрокаФайла, Объект.КолонкаДата);
Если ТекЯчейка.СодержитЗначение И ТипЗнч(ТекЯчейка.Значение) = Тип("Дата") Тогда
    ТекДатаГотовая = Формат(ТекЯчейка.Значение, "ДФ=yyyyMMdd");
Иначе
    // Попытка разбора текста, если значение не определено
    ТекДатаТекст = СокрЛП(ТекЯчейка.Текст);
    // Добавьте здесь проверку СтрРазделить с условием на количество элементов
КонецЕсли;

Помните, что свойство Текст зависит от того, как данные отображаются в табличном документе 1С, а свойство Значение несет в себе типизированные данные, извлеченные напрямую из формата XLSX.

Итоговый алгоритм решения

  1. Загрузка: Помещаем файл во временное хранилище на клиенте и передаем адрес на сервер.
  2. Чтение: На сервере создаем ТабличныйДокумент и используем Прочитать().
  3. Выбор листа: Обращаемся к коллекции Области по индексу НужныйНомер - 1.
  4. Создание подмножества: Используем ПолучитьОбласть по координатам Верх, Лево, Низ, Право и выводим её в новый ТабличныйДокумент.
  5. Обработка: В цикле обходим строки нового документа, начиная с первой, и извлекаем данные через свойства Текст или Значение.

Такой подход обеспечивает высокую скорость работы, независимость от установленного Microsoft Office и корректную работу с индексацией строк даже в многостраничных файлах сложной структуры.

← На главную