При работе с файлами Excel в среде 1С:Предприятие часто возникает задача программного изменения структуры документа: удаления лишних строк, очистки данных или переформирования реестров. Особенно остро этот вопрос стоит при работе на серверах под управлением Linux, где мы лишены возможности использовать привычные COM-объекты (библиотеки Excel.Application). В таких случаях единственным надежным инструментом остается объект ТабличныйДокумент.
В этой статье мы подробно разберем, как правильно удалять строки в табличном документе, рассмотрим нюансы работы индексов и выясним, какой метод эффективнее при обработке больших массивов данных.
Самый очевидный способ удалить строку — воспользоваться встроенным методом УдалитьОбласть. Однако здесь кроется главная ловушка для начинающих разработчиков: изменение индексов строк в процессе обхода. Рассмотрим ситуацию подробнее.
Когда мы удаляем, например, 10-ю строку, 11-я строка тут же становится 10-й, 12-я — 11-й и так далее. Если наш цикл идет «сверху вниз» (от 1 к 100), то после удаления 10-й строки счетчик перейдет к 11-й, но на самом деле это будет бывшая 12-я строка. В результате мы пропустим одну строку для проверки.
Правильное решение: всегда выполнять обход коллекции с конца (в обратном порядке). Разберем по шагам, как это реализовать в коде.
// Предположим, табДок уже прочитан из файла Excel
КоличествоСтрок = табДок.ВысотаТаблицы;
// Обходим таблицу с конца к началу, чтобы индексы не «уплывали»
Для Счетчик = -КоличествоСтрок По -1 Цикл
НомерСтроки = -Счетчик;
// Получаем значение из нужной колонки (например, колонки 2)
ТекстЯчейки = табДок.Область(НомерСтроки, 2).Текст;
// Условие для удаления (например, если ячейка пустая или содержит определенный текст)
Если ТекстЯчейки = "Удалить" Тогда
// Определяем область всей строки
// Область(Верх, Лево, Низ, Право)
ОбластьДляУдаления = табДок.Область(НомерСтроки, , НомерСтроки, );
// Удаляем область со смещением строк вверх
табДок.УдалитьОбласть(ОбластьДляУдаления, ТипСмещенияТабличногоДокумента.ПоВертикали);
КонецЕсли;
КонецЦикла;
Проанализируем параметры метода УдалитьОбласть. Вторым параметром крайне важно передать системное перечисление ТипСмещенияТабличногоДокумента.ПоВертикали. Это гарантирует, что нижние строки «подтянутся» вверх, заполняя образовавшееся пустое пространство, а не просто очистят содержимое ячеек.
Если нам нужно удалить большое количество строк, идущих подряд, вызывать метод УдалитьОбласть для каждой строки в отдельности — плохая практика с точки зрения производительности. Каждый вызов заставляет систему пересчитывать структуру всего документа.
Выясним причину замедления: при каждом удалении 1С обновляет связи всех ячеек, форматов и именованных областей. Если мы знаем, что нам нужно удалить диапазон с 10-й по 50-ю строку, гораздо эффективнее сделать это одним вызовом:
// Удаление диапазона строк с 10 по 50 включительно
ОбластьДиапазон = табДок.Область(10, , 50, );
табДок.УдалитьОбласть(ОбластьДиапазон, ТипСмещенияТабличногоДокумента.ПоВертикали);
Рассмотрим ситуацию, когда строки для удаления разбросаны. В таком случае мы можем накапливать индексы идущих подряд строк и удалять их блоками, что значительно ускорит работу на «тяжелых» файлах.
Как отметили эксперты в обсуждении, иногда проще и быстрее не удалять ненужное, а копировать нужное. Этот метод предпочтителен, если удаляемых строк больше, чем тех, что нужно оставить, или если документ содержит сложное форматирование, которое «ломается» при массовом удалении.
Разберем алгоритм совместной работы с двумя табличными документами:
ТабличныйДокумент.Вывести().
ТабДокИсточник = Новый ТабличныйДокумент;
ТабДокИсточник.Прочитать(ПутьКФайлу);
ТабДокРезультат = Новый ТабличныйДокумент;
КоличествоСтрок = ТабДокИсточник.ВысотаТаблицы;
Для НомерСтроки = 1 По КоличествоСтрок Цикл
// Проверяем условие сохранения строки
Если СтрокаДолжнаОстаться(ТабДокИсточник, НомерСтроки) Тогда
// Получаем область текущей строки целиком
ОбластьСтроки = ТабДокИсточник.Область(НомерСтроки, , НомерСтроки, );
// Выводим ее в новый документ
ТабДокРезультат.Вывести(ОбластьСтроки);
КонецЕсли;
КонецЦикла;
// Сохраняем результат
ТабДокРезультат.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.XLSX);
Метод Вывести хорош тем, что он автоматически управляет индексами в целевом документе, добавляя строки одну за другой в конец таблицы. Это избавляет разработчика от необходимости следить за смещением индексов.
Поскольку автор вопроса упомянул работу на Linux, важно учитывать специфику платформы 1С при работе с файлами:
ТипФайлаТабличногоДокумента.XLSX.usr1cv8 (или тот, под которым запущен сервер 1С) имеет права на чтение и запись в папку, где лежит временный файл Excel./home/doc.xlsx и /home/Doc.xlsx — это разные файлы.Проанализируем ситуацию: какой метод выбрать? Если в документе 100-500 строк, разница между УдалитьОбласть и Вывести будет незаметна. Однако на реестрах в 10 000 строк и более:
1. УдалитьОбласть: работает медленно из-за постоянной перестройки индексов. Время выполнения растет в геометрической прогрессии от количества строк.
2. Вывести (Копирование): работает линейно и стабильно быстро. Это предпочтительный метод для высоконагруженных систем.
Таким образом, для качественного решения задачи мы рекомендуем использовать метод обратного цикла для простых задач и метод копирования в новый документ для обработки больших массивов данных. Это обеспечит стабильную работу вашего кода как на Windows, так и на Linux-серверах.