Загрузка данных из внешних файлов, таких как Excel, — одна из самых частых задач разработчика 1С. Несмотря на наличие множества готовых инструментов, при написании собственного алгоритма часто возникают трудности: то считываются лишние пустые строки, то данные не попадают в таблицу значений из-за несовпадения типов, то файл вовсе не открывается на сервере. В этой статье мы подробно разберем, как реализовать надежный механизм загрузки данных, используя объект ТабличныйДокумент.
В управляемых формах работа с файловой системой на сервере ограничена. Поэтому первым делом нам необходимо передать файл с компьютера пользователя на серверную сторону. Рассмотрим, как это сделать правильно, используя ДвоичныеДанные. Проанализируем типичный алгоритм инициализации процесса:
&НаКлиенте
Процедура Загрузить(Команда)
Если НЕ ПроверкаКаталога() Тогда
Возврат;
КонецЕсли;
// Путь к файлу на компьютере пользователя
ПутьКФайлу = Объект.КаталогСФайлом;
ФайлИнфо = Новый Файл(ПутьКФайлу);
// Преобразуем файл в двоичные данные для передачи на сервер
ДвоичныеДанные = Новый ДвоичныеДанные(ПутьКФайлу);
// Вызываем серверную процедуру, передавая данные и расширение файла
ЗагрузитьДанныеНаСервере(ДвоичныеДанные, ФайлИнфо.Расширение);
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Загрузка окончена.");
КонецПроцедуры
Использование расширения файла крайне важно, так как метод ПолучитьИмяВременногоФайла() на сервере должен знать, в каком формате сохранить данные, чтобы 1С смогла корректно их интерпретировать.
На сервере мы сохраняем полученные двоичные данные во временный файл и используем встроенные возможности 1С для чтения XLSX без использования COM-объектов. Это позволяет коду работать быстро и не зависеть от наличия установленного Microsoft Excel на сервере. Рассмотрим основные шаги:
ТабличныйДокумент.
&НаСервере
Процедура ЗагрузитьДанныеНаСервере(ДвоичныеДанные, Расширение)
// Создаем временный файл
ИмяВременногоФайла = ПолучитьИмяВременногоФайла(Расширение);
ДвоичныеДанные.Записать(ИмяВременногоФайла);
ТабДок = Новый ТабличныйДокумент;
Попытка
// Читаем данные. Используем способ "Текст", если важны форматы Excel
ТабДок.Прочитать(ИмяВременногоФайла, СпособЧтенияЗначенийТабличногоДокумента.Текст);
Исключение
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Ошибка чтения файла: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// После чтения временный файл больше не нужен
УдалитьФайлы(ИмяВременногоФайла);
// Переходим к разбору данных
ОбработатьТабличныйДокумент(ТабДок);
КонецПроцедуры
Часто пользователи сталкиваются с тем, что в файле визуально 40 строк, а 1С считывает 500 или даже 1000. Разберем причину этого явления. Excel хранит информацию об "использованной области" (UsedRange). Если пользователь когда-то ввел данные в 500-ю строку, а потом удалил их кнопкой Delete, Excel все равно считает эту строку активной. ТабличныйДокумент.ВысотаТаблицы вернет именно это значение.
Для решения этой проблемы мы применим алгоритм ручного обхода строк с проверкой заполненности ключевых ячеек. Мы проанализируем каждую строку и будем добавлять данные в ТаблицаЗначений только в том случае, если они содержат смысл.
При заполнении ТаблицыЗначений (ТЗ) критически важно правильно определить типы колонок. Если мы планируем загружать суммы, колонка должна иметь тип Число. Если имена — Строка. Выясним причину частой ошибки начинающих разработчиков: при использовании метода Вставить() для колонок ТЗ первым параметром обязательно должен идти индекс (номер позиции), а вторым — имя колонки.
Рассмотрим правильный пример инициализации ТЗ и обхода данных:
Процедура ОбработатьТабличныйДокумент(ТабДок)
ТЗ = Новый ТаблицаЗначений;
// Используем метод Добавить(), если порядок колонок не критичен
ТЗ.Колонки.Добавить("Код", Новый ОписаниеТипов("Строка"));
ТЗ.Колонки.Добавить("Сотрудник", Новый ОписаниеТипов("Строка"));
ТЗ.Колонки.Добавить("Результат", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));
ВсегоСтрок = ТабДок.ВысотаТаблицы;
// Начинаем со второй строки, предполагая, что первая - заголовок
Для НомерСтроки = 2 По ВсегоСтрок Цикл
// Получаем текст из ячеек
ТекстКод = СокрЛП(ТабДок.Область(НомерСтроки, 1).Текст);
ТекстСотрудник = СокрЛП(ТабДок.Область(НомерСтроки, 2).Текст);
// Проверка на пустую строку: если ключевые поля пусты - пропускаем
Если ПустаяСтрока(ТекстКод) И ПустаяСтрока(ТекстСотрудник) Тогда
Продолжить;
КонецЕсли;
НоваяСтр = ТЗ.Добавить();
НоваяСтр.Код = ТекстКод;
НоваяСтр.Сотрудник = ТекстСотрудник;
// Для числовых полей желательно использовать свойство Значение или проверку
ЗначениеРезультат = ТабДок.Область(НомерСтроки, 3).Текст;
// Очищаем строку от лишних символов (неразрывных пробелов), характерных для Excel
ЗначениеРезультат = СтрЗаменить(ЗначениеРезультат, Символы.НПП, "");
НоваяСтр.Результат = Число(ЗначениеРезультат);
КонецЦикла;
// Загружаем полученную таблицу в объект (например, в табличную часть формы)
Объект.СписокДанных.Загрузить(ТЗ);
КонецПроцедуры
Если код выполняется на сервере, стандартные методы вывода сообщений или Предупреждение() работать не будут. Для отладки во внешних обработках рекомендуется использовать следующие приемы:
ТабДок.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.MXL). Убедитесь, что у службы 1С есть права на запись в этот каталог.ЗаписьЖурналаРегистрации(), чтобы отследить значения переменных в процессе выполнения цикла.-debug в строке запуска службы).Проанализируем ситуацию, когда данные в Excel содержат "мусор". При копировании данных из других программ в ячейках часто появляются скрытые символы. Важный момент: стандартная функция СокрЛП() удаляет обычные пробелы, но не справляется с "неразрывным пробелом" (код 160), который Excel часто подставляет как разделитель разрядов в числах. Перед преобразованием текста в число всегда выполняйте замену этого символа на пустую строку.
Также хорошим тоном считается использование функции-помощника для получения данных ячейки. Это делает код чище и позволяет централизованно обрабатывать ошибки чтения:
Функция ПолучитьТекстИзОбласти(пТабДок, Стр, Кол)
Попытка
Текст = пТабДок.Область("R" + Формат(Стр, "ЧГ=") + "C" + Формат(Кол, "ЧГ=")).Текст;
Возврат СокрЛП(Текст);
Исключение
Возврат "";
КонецПопытки;
КонецФункции
Подводя итог, мы выяснили, что наиболее стабильный способ загрузки из Excel — это передача файла как ДвоичныеДанные, чтение через ТабличныйДокумент на сервере и последующий построчный обход с ручной проверкой на пустые строки и очисткой данных от невидимых символов. Такой подход гарантирует, что ваша обработка не "сломается" при изменении настроек Excel или переносе базы на Linux-сервер.