Довольно часто перед разработчиками встает задача загрузки данных из файлов Excel в конфигурацию 1С. Казалось бы, платформа предоставляет удобные штатные средства для чтения формата .xlsx, однако на практике новички допускают ряд критических ошибок, которые приводят к замедлению работы программы, утечкам памяти и искажению данных (например, потере ведущих нулей в ИНН). Разберем по шагам конкретный пример из практики, проанализируем ошибки в коде и выясним, как правильно реализовать данный механизм.
Рассмотрим фрагмент кода, в котором разработчик пытается прочитать файл Excel и загрузить из него две колонки (ИНН и КПП) в табличную часть клиентов. Посмотрим на первоначальный вариант:
ТабДок = Новый ТабличныйДокумент;
Попытка
ТабДок.Прочитать(ПутьКФайлу, СпособЧтенияЗначенийТабличногоДокумента.Значение);
Исключение
// обработка ошибки
КонецПопытки;
//Создадим ТЗ куда будем собирать инфу
Таб = Новый ТаблицаЗначений;
Таб.Колонки.Добавить("ИНН",Новый ОписаниеТипов("Строка"));
Таб.Колонки.Добавить("КПП",Новый ОписаниеТипов("Строка"));
КолСтр = ТабДок.ВысотаТаблицы;
Для Сч = 2 по КолСтр Цикл
Попытка
ТБ = ТЧКлиенты.Добавить;
ТБ.ИНН = Строка(ТабДок.ПолучитьОбласть("R" + Формат(Сч, "ЧГ=0") + "C" + 1).ТекущаяОбласть.Текст);
ТБ.КПП = Число(ТабДок.ПолучитьОбласть("R" + Формат(Сч, "ЧГ=0") + "C" + 2).ТекущаяОбласть.Текст);
Исключение
// обработка ошибки
КонецПопытки;
КонецЦикла;
Проанализируем ситуацию. В коде сразу бросается в глаза серьезная архитектурная недоработка: разработчик инициализирует таблицу значений Таб, но внутри цикла почему-то добавляет строки напрямую в реквизит формы ТЧКлиенты. Добавление строк непосредственно в табличную часть на форме внутри большого цикла — это плохая практика, так как она вызывает постоянную перерисовку интерфейса и сильно замедляет работу. Правильнее сначала собрать все данные в оперативную память (в таблицу значений), а затем загрузить их разом.
Разберем самую ресурсоемкую ошибку в приведенном алгоритме. В цикле используется конструкция ТабДок.ПолучитьОбласть(...).ТекущаяОбласть.Текст. Выясним причину, почему так делать категорически не рекомендуется.
Разница между этими методами огромна:
ТабличныйДокумент в оперативной памяти. Если в файле 10 000 строк, система 20 000 раз создаст новый табличный документ ради того, чтобы прочитать текст одной ячейки. Это приведет к колоссальным "тормозам".Для оптимизации чтения всегда следует использовать ТабДок.Область(НомерСтроки, НомерКолонки).Текст или адресацию в формате R1C1: ТабДок.Область("R" + Сч + "C1").Текст.
Посмотрим на то, как происходит само чтение. В начале разработчик использует СпособЧтенияЗначенийТабличногоДокумента.Значение. Этот способ заставляет 1С пытаться самостоятельно определить тип данных в ячейке. Для финансовых показателей или дат это удобно, но для ИНН и КПП — губительно.
Если ИНН начинается с нуля (например, "0123456789") и Excel или 1С интерпретируют его как число, то ведущий нуль будет отброшен, и мы получим "123456789", что является некорректным ИНН. Более того, длинные числа могут быть представлены в экспоненциальном формате (например, 7.7E+09). Поэтому при загрузке текстовых идентификаторов (кодов, ИНН, КПП, артикулов) настоятельно рекомендуем использовать СпособЧтенияЗначенийТабличногоДокумента.Текст.
Кроме того, при конвертации чисел в строку с помощью функции Строка() часто появляются неразрывные пробелы (разделители разрядов). Чтобы от них избавиться, применяют функцию замены: СтрЗаменить(ТекстЯчейки, Символы.НПП, "").
В коде используется свойство ТабДок.ВысотаТаблицы для определения количества итераций цикла. Проанализируем, в чем здесь подвох. В Excel пользователи часто удаляют данные из строк кнопкой Delete, при этом форматирование (границы, заливка) остается. Свойство ВысотаТаблицы вернет номер последней отформатированной строки, даже если она пустая. Из-за этого цикл будет обрабатывать тысячи пустых строк.
Чтобы избежать этого, добавим проверку ключевого поля (в нашем случае ИНН) на заполненность. Если строка пустая — прерываем цикл.
Соберем все рекомендации воедино и напишем корректный, быстрый и отказоустойчивый код. Мы будем читать документ как текст, использовать метод Область(), заполнять промежуточную таблицу значений и проверять строки на пустоту.
// 1. Читаем файл строго как Текст, чтобы не потерять нули в ИНН
ТабДок = Новый ТабличныйДокумент;
Попытка
ТабДок.Прочитать(ПутьКФайлу, СпособЧтенияЗначенийТабличногоДокумента.Текст);
Исключение
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = ОписаниеОшибки();
Сообщение.Сообщить();
Возврат;
КонецПопытки;
// 2. Создаем и настраиваем таблицу значений в памяти
ТабДанных = Новый ТаблицаЗначений;
ТабДанных.Колонки.Добавить("ИНН", Новый ОписаниеТипов("Строка"));
ТабДанных.Колонки.Добавить("КПП", Новый ОписаниеТипов("Строка"));
КолСтр = ТабДок.ВысотаТаблицы;
// 3. Обходим строки в табличном документе
Для Сч = 2 По КолСтр Цикл
// Используем быстрый метод Область() вместо ресурсоемкого ПолучитьОбласть()
ЗначениеИНН = СокрЛП(ТабДок.Область(Сч, 1).Текст);
ЗначениеКПП = СокрЛП(ТабДок.Область(Сч, 2).Текст);
// Очищаем от возможных неразрывных пробелов
ЗначениеИНН = СтрЗаменить(ЗначениеИНН, Символы.НПП, "");
ЗначениеКПП = СтрЗаменить(ЗначениеКПП, Символы.НПП, "");
// Защита от пустых строк с оставшимся форматированием Excel
Если ПустаяСтрока(ЗначениеИНН) И ПустаяСтрока(ЗначениеКПП) Тогда
Продолжить; // Или Прервать, если пустые строки означают конец файла
КонецЕсли;
// Добавляем очищенные данные в ТЗ
НоваяСтрока = ТабДанных.Добавить();
НоваяСтрока.ИНН = ЗначениеИНН;
НоваяСтрока.КПП = ЗначениеКПП;
КонецЦикла;
// 4. Единоразово загружаем подготовленные данные в визуальную часть (на форму)
ТЧКлиенты.Загрузить(ТабДанных);
Применяя данный подход, вы обеспечите стабильную и быструю работу загрузки данных из Excel. Использование правильных методов работы с объектом ТабличныйДокумент и разделение логики сбора данных и отображения их на форме — залог качественного и профессионального кода в среде 1С.