gifts2017

Универсальное решение работы с Ексель

Опубликовал Александр Хомяк (logarifm) в раздел Программирование - Практика программирования

Маленькая функция для чтения Ексель!

Хочу поделиться опытом. Вот смотрю - на форуме все появляются новые и новые методы работы с Екселем - в основном, все обработки. А вот пришлось мне делать много импортов из екселя и пришлось постоянно в обработки писать кучу одного и того же кода. Потом я сделал одну, универсальную функцию, которая читает данные екселя и отдает таблицу значений.

Итак, рассказываю как работает данная функция.

  1. ИмяФайла - обязательный параметр;
  2. НачСтрока - обязательный параметр, здесь указывается начало строки с которого необходимо произвести чтение файла;
  3. КонСтрока - не обязательный параметр (если он опущен то строка будет определятся автоматически как последняя заполненная в файле, крайняя правая ячейка);
  4. НомЛиста - не обязательный параметр (если он опущен то будут данные загружаться со всех листов);
  5. СтруктураКолонок - это список значений, который вы задаете, например:
НомерКолонкиАртикул = 1;
НомерКолонкиНаименование = 2;
НомерКолонкиКодПрограммы1С = 3;

СтруктураКолонок = Новый СписокЗначений;

СтруктураКолонок.Добавить(НомерКолонкиАртикул,"Артикул");
СтруктураКолонок.Добавить(НомерКолонкиНаименование,"Наименование");
СтруктураКолонок.Добавить(НомерКолонкиКодПрограммы1С,"КодПрограммы1С");

ТаблицаФайла = ОбщийМодуль.ОбработкаИмпортаФайлаЕксель(ИмяФайла,НачСтрока,КонСтрока,НомЛиста,СтруктураКолонок);

После работы функции ТаблицаФайла будет содержать структуру колонок с данными, то есть "Артикул, Наименование, КодПрограммы1С". Теперь вы спокойно делаете простенький цикл обхода таблице значений по вашему вкусу!

//Обработка импорта файла Ексель
// СтруктураКолонок, должен содержать
//        Представление: "Наименование колонки";
//        Значение: "Номер колонки"
//            если номер колонки не указан или передан служебный символ "#", будет создана просто пустая колонка
//
Функция ОбработкаИмпортаФайлаЕксель(ИмяФайла,НачСтрока=1,КонСтрока=0,НомерЛиста=0,СтруктураКолонок) Экспорт
    
    Если НЕ ЗначениеЗаполнено(ИмяФайла) Тогда
        #Если Клиент Тогда
            Предупреждение("Необходимо указать путь к файлу",3);
        #КонецЕсли   
        Возврат Неопределено;
    КонецЕсли;   
    
    Если НЕ ЗначениеЗаполнено(СтруктураКолонок) Тогда
        #Если Клиент Тогда
            Предупреждение("Необходимо указать структуру колонок",3);
        #КонецЕсли   
        Возврат Неопределено;
    КонецЕсли;
    
    //Разбор листов
    СписокИспользуемыхЛистов = Новый СписокЗначений;
    КнигаExcel = ПолучитьCOMОбъект(ИмяФайла);
    //есть несколько вариантов исчисления:
    //1.Номер последней загружаемой строки. Если не указан, то ищется как последнее
    //  не пустой код производителя, тоесть не пустое последнее значение. А номер Листа определен
    Если (ЗначениеЗаполнено(НомерЛиста))
        И    (НЕ ЗначениеЗаполнено(КонСтрока))    Тогда
        //пользователь указал лист, но не указал КонСтрока
        Лист = КнигаExcel.Worksheets(НомерЛиста);
        ИспользуемыйДиапазон = Лист.UsedRange;
        ПоследняяЯчейка      = ИспользуемыйДиапазон.SpecialCells(11); //последня правая нижняя ячейка
        Если ((ИспользуемыйДиапазон.Address<>ПоследняяЯчейка.Address) ИЛИ  (ПоследняяЯчейка.Text<>"")) Тогда
            СписокИспользуемыхЛистов.Добавить(ИспользуемыйДиапазон.Rows.Count(),Лист.Name);    
        Иначе
            #Если Клиент Тогда
                Предупреждение("Не могу опредилить конечную строку");
            #КонецЕсли
            Возврат Неопределено;
        КонецЕсли;
    ИначеЕсли (НЕ ЗначениеЗаполнено(НомерЛиста))
        И         (ЗначениеЗаполнено(КонСтрока))   Тогда
        //во всех листах, но с определенными КонСтрока
        Для  ИндексЛиста = 1 По КнигаExcel.Worksheets.Count Цикл
            Лист=КнигаExcel.Worksheets(ИндексЛиста);
            СписокИспользуемыхЛистов.Добавить(КонСтрока,Лист.Name);    
        КонецЦикла;
    ИначеЕсли (НЕ ЗначениеЗаполнено(НомерЛиста))
        И         (НЕ ЗначениеЗаполнено(КонСтрока))   Тогда   
        //во всех листах и нужно в каждом из них найти КонСТрока
        Для  ИндексЛиста = 1 По КнигаExcel.Worksheets.Count Цикл
            Лист = КнигаExcel.Worksheets(ИндексЛиста);
            ИспользуемыйДиапазон = Лист.UsedRange;
            ПоследняяЯчейка      = ИспользуемыйДиапазон.SpecialCells(11);
            Если ((ИспользуемыйДиапазон.Address<>ПоследняяЯчейка.Address) ИЛИ  (ПоследняяЯчейка.Text<>"")) Тогда
                СписокИспользуемыхЛистов.Добавить(ИспользуемыйДиапазон.Rows.Count(),Лист.Name);    
            КонецЕсли;
        КонецЦикла;
    ИначеЕсли (ЗначениеЗаполнено(НомерЛиста))
        И         (ЗначениеЗаполнено(КонСтрока))   Тогда
        //пользователь указал и Лист и КонСтрочку
        Лист = КнигаExcel.Worksheets(НомерЛиста);
        СписокИспользуемыхЛистов.Добавить(КонСтрока,Лист.Name);
    КонецЕсли;   
    
    // по п. 1) КвоЛистов=СписокИспользуемыхЛистов.РазмерСписка();
    // по п. 2) КвоСтрок=СписокИспользуемыхЛистов.Получить(ИмяЛиста);
    КонСтрокаДляПрогреса = 0;
    Для Каждого НомераКонСтроки Из СписокИспользуемыхЛистов Цикл
        КонСтрокаДляПрогреса = КонСтрокаДляПрогреса + НомераКонСтроки.Значение;
    КонецЦикла;   
    
    мФормаИндикатора = Неопределено;
    #Если Клиент Тогда
        
        Попытка
            мФормаИндикатора = ПолучитьОбщуюФорму("ХодВыполненияОбработкиДанных");
            мФормаИндикатора.КомментарийОбработкиДанных = "Выполняется обработка импорта с файла xls";
            мФормаИндикатора.Значение = 0;
            мФормаИндикатора.МаксимальноеЗначение = КонСтрокаДляПрогреса;
            мФормаИндикатора.Открыть();
        Исключение
            мФормаИндикатора = Неопределено;
        КонецПопытки;
        
    #КонецЕсли
    
    ТаблицаРезультатов = Новый ТаблицаЗначений;
    ТаблицаРезультатов.Колонки.Добавить("Лист");
    
    Для Каждого СтрокаКолонки Из СтруктураКолонок Цикл
        Инд = СтрокаКолонки.Представление;
        ТаблицаРезультатов.Колонки.Добавить(Инд);
    КонецЦикла;
    
    Для Каждого НомераКонСтроки Из СписокИспользуемыхЛистов Цикл
        НомерЛиста = НомераКонСтроки.Представление;
        КонСтрока  = НомераКонСтроки.Значение;
        
        СостояниеПрогреса = 0;
        
        Для НомерОбработанойСтроки = НачСтрока По КонСтрока Цикл
            
            #Если Клиент Тогда
                ОбработкаПрерыванияПользователя();
            #КонецЕсли
            
            СостояниеПрогреса = СостояниеПрогреса + 1;
            #Если Клиент Тогда
                Если НЕ мФормаИндикатора = Неопределено Тогда
                    мФормаИндикатора.Значение = мФормаИндикатора.Значение + 1;
                КонецЕсли;
            #КонецЕсли
            
            НоваяСтрока = ТаблицаРезультатов.Добавить();
            НоваяСтрока.Лист = НомерЛиста;
            
            Для Каждого ИндетификатораКолонки Из СтруктураКолонок Цикл
                iCount         = ИндетификатораКолонки.Значение;
                Если (НЕ ЗначениеЗаполнено(iCount))
                    ИЛИ (iCount = "#") Тогда
                    //это структура пустой колонки
                    Продолжить;
                КонецЕсли;   
                ЗначениеЗаписи = СтрЗаменить(СокрЛП(КнигаExcel.Sheets(НомерЛиста).Cells(НомерОбработанойСтроки,iCount).Value),Символ(160),"");
                НоваяСтрока[ИндетификатораКолонки.Представление] = ЗначениеЗаписи;
            КонецЦикла;
            
        КонецЦикла;
    КонецЦикла;
    
    #Если Клиент Тогда
        Состояние("Завершено!");
        Если НЕ мФормаИндикатора = Неопределено Тогда
            мФормаИндикатора.Закрыть();
        КонецЕсли;
    #КонецЕсли
    
    Возврат ТаблицаРезультатов;
    
КонецФункции

Хочу подчеркнуть, что ход выполнения состояния работает только в типовых конфигурациях которые оснащены общей формой "ХодВыполненияОбработкиДанных", в противном случае часть кода где идет обращение к данной форме можете удалить и подставить свой если такой имеется!

См. также

Подписаться Добавить вознаграждение

Комментарии

1. GSoft. (GSoft) 21.05.09 01:49
поменяй плиз раздел на 1С+Excel - упростишь при поиске многим жизнь))
2. Василий Демидов (Душелов) 21.05.09 01:52
Ага, еще стоит сказать, что это для типовой, в которой есть обработка "ХодВыполненияОбработкиДанных"
3. oleksandr.homyak (logarifm) 21.05.09 02:01
(1) В статьях нету почему-то выбора такой рубрики, вот и пришлось указать "Автоматизация"
4. Дмитрий Калачев (wildhog) 21.05.09 09:41
если правильно понял, чтение из Excel поячеечное?
Почему не используется объект COMSafeArray?
5. GSoft. (GSoft) 21.05.09 09:52
(0, 2) а что мешает типовую процедуру сюда выложить
6. Василий Демидов (Душелов) 21.05.09 11:12
(5) Как обычно - я вставил себе в конфигурацию, а оно не работает - ругается!
И список того, на что ругается :)
7. GSoft. (GSoft) 21.05.09 12:48
8. Дмитрий Елисеев (w-divin) 17.10.09 23:46
"Вообще вот нечем народу занятся" (с) аффтар

Мне это не нужно - получите минус...
9. Юрий Пысларь (DirectAuto) 25.05.12 15:26
Просто и сердито. Для 99% случаев то, что доктор прописал.
Для более быстрой работы с Екселем следует юзать технологию ADO
через набор системных драйверов ODBC.
(для этого спросите у яндекса: "1С 8 ODBC подключение к Эксель")
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа