Надеюсь, что статья поможет вам сократить время разработки.
Особая благодарность Андрею М. за публикацию //infostart.ru/public/163640/
В данной статье приведен функционал, с помощью которого в обработке
"Импорт из EXCEL (xls) в 1С"
производится считывание данных из файлов табличного типа *xls.
Есть множество статей на эту тему:
— Метод "MS ADO" (Чтение файлов xls, xlsx средствами Microsoft ADO): //infostart.ru/public/163640/
— Метод "MS EXCEL" (Чтение файлов xls, xlsx с картинками средствами Microsoft Office): //infostart.ru/public/163641/
— Метод "LO CALC" (Чтение файлов xls, xlsx, ods, sxc с картинками средствами LibreOffice): //infostart.ru/public/163642/
— Метод "NativeXLSX" (Чтение файлов xlsx с картинками средствами 1С. ПостроительDOM): //infostart.ru/public/300092/
— Метод "NativeXLSX". Предыдущий вариант (Чтение файлов xlsx средствами 1С. ЧтениеXML)://infostart.ru/public/225624/
— Метод "Excel1C" (Загрузка на платформе 8.3.6 с картинками. Чтение файлов xls, xlsx, ods): //infostart.ru/public/341855/
— Список листов файла: //infostart.ru/public/163724/
Но всегда возникают какие-то проблемы:
При загрузке из EXCEL в 1С методом MS ADODB.Connection столкнулся со следующим:
-
пользователь выделил цветом всю таблицу Excel, что привело к считыванию всего листа книги.
-
EOF() оказался гораздо дальше чем реально пользователь видел при визуальном осмотре таблицы Excel, т. е. загружались пустые строки
-
необходимо было очищать таблицу от строк с наименованиями колонок
Это моя первая публикация. Буду рад вашим исправлениям и комментариям. P.S. Код написан только для расширения .xls.
&НаКлиенте
Процедура ЗагрузитьExcel(Команда)
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Диалог.Заголовок = "Выберите файл";
Диалог.Фильтр = "|*.xls";
Диалог.МножественныйВыбор = Ложь;
Если Диалог.Выбрать() Тогда
Адрес = "";
ПоместитьФайл(Адрес,Диалог.ПолноеИмяФайла,,Ложь);
ЗагрузитьНаСервере(Адрес);
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ЗагрузитьНаСервере(Адрес)
ТЗ = ЗагрузитьТаблицуExcelНаСервере(Адрес);
//далее код работы с ТЗ ....
КонецПроцедуры
&НаСервереБезКонтекста
Функция ЗагрузитьТаблицуExcelНаСервере(Адрес)
ФайлИзХранилища = ПолучитьИзВременногоХранилища(Адрес);
ВременныйФайл = ПолучитьИмяВременногоФайла("xls");
//Сохранение во временнный файл на диске
ФайлИзХранилища.Записать(ВременныйФайл);
//Если опущен, тогда 1-й лист
еБаза=Новый COMОбъект("ADODB.Connection");
СтрокаПодключения = "
|Provider=Microsoft.Jet.OLEDB.4.0;
|Data Source="+ВременныйФайл+";
|Extended Properties=""Excel 8.0;IMEX=1;HDR=NO;"";";
Попытка
еБаза.Open(СтрокаПодключения);
Исключение
СтрокаПодключения = "
|Provider=Microsoft.ACE.OLEDB.12.0;
|Data Source="+ПутьКФайлу+";
|Extended Properties=""Excel 12.0;IMEX=1;HDR="+?(HDR,"Yes","No")+";"";";
Попытка
еБаза.Open(СтрокаПодключения);
Исключение
Сообщить(ОписаниеОшибки());
КонецПопытки;
КонецПопытки;
Catalog = Новый COMОбъект("ADOX.Catalog");
Catalog.ActiveConnection = еБаза;
лСпис=Новый СписокЗначений;
лИмяЛиста="";
Для iCount = 0 По Catalog.Tables.Count-1 Цикл
Если Catalog.Tables.Item(iCount).Type <> "VIEW" Тогда
лСпис.Добавить(Catalog.Tables.Item(iCount).Name);
КонецЕсли;
КонецЦикла;
Если лСпис.Количество()>0 И лИмяЛиста="" тогда
лИмяЛиста = лСпис[0];
Конецесли;
Catalog=Неопределено;
лСтрВнЗапроса="select * from ["+лИмяЛиста+"]";
RS = Новый COMОбъект("ADODB.Recordset");
rs.Open(лСтрВнЗапроса,еБаза,0);
лТз=Новый ТаблицаЗначений;
ЕстьОшибкиВИмениКолонки=Ложь;
Для iCount = 0 По rs.Fields.Count-1 Цикл
Если СокрЛП(rs.Fields.Item(iCount).Value) = "" Тогда //прервём на пустой ячейке имени колонки
Прервать;
КонецЕсли;
Попытка
лТз.Колонки.Добавить(rs.Fields.Item(iCount).Value,, rs.Fields.Item(iCount).Name); // Считаем что в первой строке заголовки колонок
Исключение
Сообщить(ОписаниеОшибки()+" «"+(rs.Fields(iCount).Value)+"»");
ЕстьОшибкиВИмениКолонки = Истина;
КонецПопытки;
КонецЦикла;
Если ЕстьОшибкиВИмениКолонки Тогда //прерываем, чтобы исправили
Возврат лТз;
КонецЕсли;
// Перебор данных
Строк=0;
rs.MoveFirst();
//пользователь выделил цветом весь лист Excel, в том числе и пустые ячейки
//добавим переменную для счета количества пустых ячеек,
//как только будет 10 пустых ячеек, считаем, что уже закончились строки в таблице
СчПустых = 0;
ПустыеСтроки = 0;
Пока rs.EOF() = 0 Цикл
СчПустых = 0;
Строк=Строк+1;
//как только будет 10 пустых ячеек, считаем, что уже закончились строки в таблице
Если ПустыеСтроки = 10 Тогда
Прервать;
КонецЕсли;
лТз.Добавить();
Для iCount = 0 По rs.Fields.Count-1 Цикл
Если СчПустых = 3 Тогда //подряд три пустых ячейки, прервём
СчПустых = 0;//уменьшим
ПустыеСтроки = ПустыеСтроки+1;
//Если три первые ячейки строки пустые, то удаляем строку
Если лТз[лтз.Количество()-1][0]=Неопределено И лТз[лтз.Количество()-1][0] = лТз[лтз.Количество()-1][1] И лТз[лтз.Количество()-1][1] = лТз[лтз.Количество()-1][2] Тогда
лТз.Удалить(лТз[лтз.Количество()-1]);
КонецЕсли;
Прервать;
КонецЕсли;
Если Строка(rs.Fields(iCount).Value) = "" Тогда
СчПустых = СчПустых+1;
Продолжить;
КонецЕсли;
Попытка
лТз[лтз.Количество()-1][iCount]=Строка(rs.Fields(iCount).Value);
ПустыеСтроки = 0;
Исключение
Прервать;
КонецПопытки;
КонецЦикла;
rs.MoveNext();
КонецЦикла;
rs=Неопределено;
еБаза.Close();
еБаза=Неопределено;
УдалитьИзВременногоХранилища(Адрес);
//Удалим первую строку с наименованием колонок
Если лТз[0][0] = лТз.Колонки[0].Имя Тогда
лТз.Удалить(лТз[0]);
КонецЕсли;
Возврат лТз;
КонецФункции
на загрузку через ADO я плюнул много лет назад, когда при первой же попытке применить сей инструмент на первом же файле (а я промучался часа четыре) — выяснилось что из прайса ~10тысяч строк возвращается тупо порядка ~4000, хотя при обычном открытии экселем и обычным чтением из экселя все нормально проходило. и ADO на ДРУГИХ файлах — нормально проходило. А вот на этом — фигушки. так как я не спец в этих делах, а загрузку надо было ставить в автомат в продакшен — ADO благословеннно почил в бозе.. так я его и не освоил…
Можно было лишние поля прямо в запросе отсеять.. Собственно, возможность указывать фильтр в запросе — одна из фишек ADO. Еще его используют когда:
http://infostart.ru/public/20090/) . Если все делать через range — в случае небольших книг по скорости не уступает ADO. Кстати, через range можно и записывать.
— надо работать с Excell на сервере (а устанавливать его на сервер нельзя)
— надо читать большие объемы, без загрузки их в память (recordset) — в этом случае быстрее работает, чем перебор строк в Excell.Application
Но не всегда ADO выгоднее — его минусы в том, что всякий раз надо муздыкаться с драйверами. Локально у себя — все отлично, только передал клиенту, начинаются вопросы «что это он про какой-то драйвер спрашивает».. Поэтому для себя определился так, что ADO применять только в двух выше описанных случаях. А если файл небольшой, и работа идет на клиенте — вполне можно использовать чтение через Excell, работая с диапазонами (
Для использования ADO нет необходимости в установке msoffice.
сам когда делал выбор адо-неадо столкнулся с тем что не нашел в АДО уровень группировки строк, который есть в ексель.аппликейшн, а мне надо было загруженную номенклатуру раскидывать по папкам + еще прибавлять к имени номенклатуры названия папок двух верхних уровней и пришлось от АДО отказываться