Почему при загрузке таблицы Excel в 1С возникают ошибки?

При загрузке из EXCEL в 1С методом MS ADODB.Connection столкнулся с некоторыми проблемами, которые попытался устранить в ниже приведенной статье.
Надеюсь, что статья поможет вам сократить время разработки.
Особая благодарность Андрею М. за публикацию //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]);
КонецЕсли;

Возврат лТз;

КонецФункции

 

4 Comments

  1. CheBurator

    на загрузку через ADO я плюнул много лет назад, когда при первой же попытке применить сей инструмент на первом же файле (а я промучался часа четыре) — выяснилось что из прайса ~10тысяч строк возвращается тупо порядка ~4000, хотя при обычном открытии экселем и обычным чтением из экселя все нормально проходило. и ADO на ДРУГИХ файлах — нормально проходило. А вот на этом — фигушки. так как я не спец в этих делах, а загрузку надо было ставить в автомат в продакшен — ADO благословеннно почил в бозе.. так я его и не освоил…

    Reply
  2. unichkin

    Можно было лишние поля прямо в запросе отсеять.. Собственно, возможность указывать фильтр в запросе — одна из фишек ADO. Еще его используют когда:

    — надо работать с Excell на сервере (а устанавливать его на сервер нельзя)

    — надо читать большие объемы, без загрузки их в память (recordset) — в этом случае быстрее работает, чем перебор строк в Excell.Application

    Но не всегда ADO выгоднее — его минусы в том, что всякий раз надо муздыкаться с драйверами. Локально у себя — все отлично, только передал клиенту, начинаются вопросы «что это он про какой-то драйвер спрашивает».. Поэтому для себя определился так, что ADO применять только в двух выше описанных случаях. А если файл небольшой, и работа идет на клиенте — вполне можно использовать чтение через Excell, работая с диапазонами (http://infostart.ru/public/20090/). Если все делать через range — в случае небольших книг по скорости не уступает ADO. Кстати, через range можно и записывать.

    Reply
  3. dakork

    Для использования ADO нет необходимости в установке msoffice.

    Reply
  4. KazanKokos

    сам когда делал выбор адо-неадо столкнулся с тем что не нашел в АДО уровень группировки строк, который есть в ексель.аппликейшн, а мне надо было загруженную номенклатуру раскидывать по папкам + еще прибавлять к имени номенклатуры названия папок двух верхних уровней и пришлось от АДО отказываться

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *