20.08.2014. Новая редакция с возможностью загрузки изображений из файла.
 
 В данной статье приведен функционал, с помощью которого в обработке
 "Импорт из EXCEL и др.источников (xls,xlsx,ods,sxc,dbf,mxl,csv,sql) в 1С": //infostart.ru/public/120961/
 производится считывание данных из файлов табличного типа *xls, *.xlsx.
 
 Методы загрузки из внешнего источника:
- Метод "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 - множество, но
 "
 — Вам билетёр нужен?
 — Был нужен, да уже взяли.
 — Может и я на что сгожусь?
 — Может и сгодишься, если скалиться не будешь ...
 "
"НЕУЛОВИМЫЕ МСТИТЕЛИ" (1966).
&НаКлиенте
 Процедура ПриОткрытии(Отказ)
     ФайлEXCEL= "D:\Товар.xls";
     ИмяЛиста = Новый Структура ("ИмяЛиста, НомерЛиста","СФКартинок (2)", 16);
     СтрокаЗаголовка = 1;
     НачСтрока = 3;
     КонСтрока = 4;
     КолвоСтрокExcel = 0;
     ЗагрузитьМетодом_MSEXCEL_НаСервере(ФайлEXCEL, ИмяЛиста, СтрокаЗаголовка, НачСтрока, КонСтрока, КолвоСтрокExcel);
 КонецПроцедуры
 
 &НаСервере
 Процедура ЗагрузитьМетодом_MSEXCEL_НаСервере(ФайлEXCEL, ИмяЛиста, СтрокаЗаголовка, НачСтрока, КонСтрока, КолвоСтрокExcel)
 
     ТаблицаРезультат = ЗагрузитьМетодом_MSEXCEL(ФайлEXCEL, ИмяЛиста, СтрокаЗаголовка, НачСтрока, КонСтрока, КолвоСтрокExcel);
 
 КонецПроцедуры
 
 // Метод "Microsoft EXCEL.Application".
  //
  // Параметры:
  //      ФайлEXCEL - Полное имя файла (путь к файлу с именем файла и расширением)
  //      ИмяНомерЛиста - Имя/Номер выбранного листа файла EXCEL.
  //      СтрокаЗаголовка (по умолчанию = 1) - Номер строки EXCEL, в которой расположены заголовки колонок.
  //          Не используется.
  //      В обработке 1-я строка анализируется для сопоставления колонок EXCEL с реквизитами 1С (справочники, докуметны, регистры).
  //      НачСтрока (по-умолчанию = 0) - Номер начальной строки, начиная с которой считываются данные из EXCEL.
  //      КонСтрока (по-умолчанию = 0) - Номер конечной строки, которой заканчиваются считываемые данные из EXCEL.
  //          Если НачСтрока=0 и КонСтрока=0, то считывается вся таблица, находящаяся на листе EXCEL.
  //      КолвоСтрокEXCEL - Количество строк на листе "ИмяЛиста" EXCEL. Возвращается в вызываемую процедуру.
  //
  // Возвращаемые значения:
  //      ТаблицаРезультат - Результат считывания с листа "ИмяЛиста" EXCEL.
  //
 &НаСервере
 Функция ЗагрузитьМетодом_MSEXCEL(Знач ФайлEXCEL, Знач ИмяНомерЛиста, Знач СтрокаЗаголовка = 1, НачСтрока = 2, КонСтрока = 0, КолвоСтрокEXCEL)
     Перем ИмяФайлаEXCEL, ИмяЛиста, НомерЛиста;
     Перем EXCELApplication, Book, Sheet;
     Перем ВсегоЛистов, НачальнаяКолонка, НачальнаяСтрока, КонечнаяКолонка, КонечнаяСтрока;
     Перем ДиапазонДанных, СтрокДиапазона, ДиапазонЗаголовка, МассивЗаголовка, МассивЗначений;
     Перем ТекИмя, ПозДоллар, Версия;
     Перем ТаблицаРезультат, МассивИменКолонок, ИмяКолонки, Колонка, Заголовок, НоваяСтрока, нСтроки;
 
     ИмяФайлаEXCEL = ПолучитьИмяФайлаБезРасширения(ФайлEXCEL);
 
     // Нумерация MS EXCEL начинается с 1.
     ИмяЛиста    = ИмяНомерЛиста.ИмяЛиста;
     НомерЛиста  = ИмяНомерЛиста.НомерЛиста;
 
     Попытка
         // Инициализация основного объекта EXCEL.Application: Открытие соединения.
         EXCELApplication = Новый COMОбъект("EXCEL.Application");
         EXCELApplication.Visible       = Ложь;
         EXCELApplication.DisplayAlerts = Ложь;
     Исключение
         Попытка
             EXCELApplication.Application.Quit();
         Исключение
         КонецПопытки;
         EXCELApplication = Неопределено;
         Сообщить(НСтр("ru = '"+ОписаниеОшибки()+"'"), СтатусСообщения.Внимание);
         Возврат Новый ТаблицаЗначений;  // В случае ошибки возвращаем пустую таблицу значений.
     КонецПопытки;
 
     // Определение версии EXCEL.
     Версия = Лев(EXCELApplication.Version,Найти(EXCELApplication.Version,".")-1);
 
     // Инициализация дочернего объекта типа Книга EXCEL.
     Book = EXCELApplication.WorkBooks.Open(ФайлEXCEL);
     ВсегоЛистов = Book.Sheets.Count;
 
     // Инициализация дочернего объекта Книги типа Лист EXCEL.
     Если Лев(ИмяЛиста, 1) = "'" И Прав(ИмяЛиста, 1) = "'" Тогда
         ИмяЛиста = УдалитьКавычки(ИмяЛиста, "'");
     КонецЕсли;
     Если Прав(ИмяЛиста, 1) = "$" Тогда
         УдалитьПоследнийСимволВСтроке(ИмяЛиста, 1);
     КонецЕсли;
     Sheet = Book.WorkSheets(ИмяЛиста);
 
     // Определение диапазона данных таблицы EXCEL.
     НачальнаяКолонка    = 1;
     НачальнаяСтрока     = 1;
     Если Версия = "8" Тогда
         КонечнаяКолонка = Sheet.Cells.CurrentRegion.Columns.Count;
         КонечнаяСтрока  = Sheet.Cells.CurrentRegion.Rows.Count;
     Иначе
         КонечнаяКолонка = Sheet.Cells.SpecialCells(11).Column;
         КонечнаяСтрока  = Sheet.Cells.SpecialCells(11).Row;
     Конецесли;
 
     // Параметр возвращаемый в вызывающую процедуру.
     КолвоСтрокEXCEL     = КонечнаяСтрока;
 
     // Проверка заполненности листа.
     Если КолвоСтрокEXCEL <= 1 И КонечнаяКолонка <= 1 Тогда
         КолвоСтрокEXCEL = 0;
         Сообщить(НСтр("ru = '" + ИмяЛиста + ": Лист, содержащий 1 строку считаем пустым.'"), СтатусСообщения.Внимание);
 
         // Завершение работы.
         // Закрытие Объектов.
         Попытка
             Book.Close();
         Исключение
         КонецПопытки;
         Попытка
             EXCELApplication.Application.Quit();
         Исключение
         КонецПопытки;
         EXCELApplication = Неопределено;
 
         Возврат Новый ТаблицаЗначений;  // В случае ошибки возвращаем пустую таблицу значений.
     КонецЕсли;
 
     НачальнаяСтрока     = ?(НачСтрока = 0   , НачальнаяСтрока   , НачСтрока);
     КонечнаяСтрока      = ?(КонСтрока = 0   , КонечнаяСтрока    , КонСтрока);
 
     КонечнаяСтрока      = ?(КонечнаяСтрока > КолвоСтрокEXCEL, КолвоСтрокEXCEL, КонечнаяСтрока);
     НачальнаяСтрока     = ?(НачальнаяСтрока > КолвоСтрокEXCEL, КолвоСтрокEXCEL, НачальнаяСтрока);
 
     // Диапазон: Считываемые данные.
     ДиапазонДанных = Sheet.Range(Sheet.Cells(НачальнаяСтрока, НачальнаяКолонка), Sheet.Cells(КонечнаяСтрока, КонечнаяКолонка));
     СтрокДиапазона = ДиапазонДанных.Rows.Count;
 
     // Создание результирующей таблицы, в которую будут записываться считанные из EXCEL данные.
     ТаблицаРезультат = Новый ТаблицаЗначений;
 
     // Формирование колонок результирующей таблицы.
 
      // "НомерСтроки" - для наглядности и удобства.
      // В зависимости от разрабатываемой обработки.
      // "Сопоставлено" - может быть другим.
      // Здесь же могут быть добавлены другие колонки, не формируемые из содержимого файла EXCEL.
     ТаблицаРезультат.Колонки.Добавить("НомерСтроки", Новый ОписаниеТипов("Число"), "№", 4);
     ТаблицаРезультат.Колонки.Добавить("Сопоставлено", Новый ОписаниеТипов("Булево"), "Сопоставлено", 1);
 
     МассивИменКолонок = Новый Массив;
     Для ит = 1 ПО КонечнаяКолонка Цикл
 
         ТекИмя = Строка(ит);
         МассивИменКолонок.Добавить(ТекИмя);
 
         Если ДиапазонДанных.Columns(ит).Hidden Тогда    // Скрытые колонки EXCEL пропустить.
             Продолжить;
         КонецЕсли;
 
         ИмяКолонки = "N" + ТекИмя;
         ТаблицаРезультат.Колонки.Добавить(ИмяКолонки);
 
     КонецЦикла;
 
     // ТаблицаРезультат: 1-я Строка-Заголовок.
      // Если в Вашей обработке в результирующей таблице в качестве 1-ой строки не нужна Строка-Заголовок, то
      // следует закомментировать следующий цикл:
     ДиапазонЗаголовка = Sheet.Range(Sheet.Cells(1, НачальнаяКолонка), Sheet.Cells(1, КонечнаяКолонка));
     МассивЗаголовка = ДиапазонЗаголовка.Value.Выгрузить();
 
     НоваяСтрока = ТаблицаРезультат.Добавить();
     НоваяСтрока.НомерСтроки = 1;
 
     ит = -1;
     Для Каждого МассивЗначений ИЗ МассивЗаголовка Цикл
 
         Для Каждого ЭлементМассива ИЗ МассивЗначений Цикл
             ит = ит + 1;
 
             ИмяКолонки = "N" + МассивИменКолонок[ит];
             Колонка = ТаблицаРезультат.Колонки.Найти(ИмяКолонки);
             Если Колонка = Неопределено Тогда   // Имена скрытых колонок отсутствуют в массиве.
                 Продолжить;
             КонецЕсли;
 
             НоваяСтрока[ИмяКолонки] = СокрЛП(ЭлементМассива);
         КонецЦикла;
 
     КонецЦикла;
 
     // ТаблицаРезультат: формирование строк по указанному диапазону: НачСтрока - КонСтрока.
 
     ДиапазонДанных = ДиапазонДанных.Value;
 
     нСтроки = НачальнаяСтрока-1;
     Для НомерСтроки = 1 ПО СтрокДиапазона Цикл
 
         нСтроки = нСтроки + 1;
         НоваяСтрока = ТаблицаРезультат.Добавить();
         НоваяСтрока.НомерСтроки = нСтроки;
 
         Для НомерКолонки = 1 ПО КонечнаяКолонка Цикл
 
             ИмяКолонки = "N" + МассивИменКолонок[НомерКолонки-1];
             Колонка = ТаблицаРезультат.Колонки.Найти(ИмяКолонки);
             Если Колонка = Неопределено Тогда   // Имена скрытых колонок отсутствуют в массиве.
                 Продолжить;
             КонецЕсли;
 
             ЗначениеЯчейки = ДиапазонДанных.GetValue(НомерКолонки, НомерСтроки);            // Считывание данных в соответствии с их типом.
 
             Если ЗначениеЯчейки = Неопределено Тогда
                 ЗначениеЯчейки = ПрочитатьКартинку_MSEXCEL(EXCELApplication, Sheet, НомерКолонки, нСтроки, ИмяФайлаEXCEL, НомерЛиста, "УИД");
             КонецЕсли;
 
             Если ЗначениеЗаполнено(ЗначениеЯчейки) Тогда
 
                 // Ширина колонки используется при формировании таблицы на форме обработки.
                 ШиринаКолонки = ТаблицаРезультат.Колонки[ИмяКолонки].Ширина;
                 ДлинаСтроки = СтрДлина(СокрЛП(ЗначениеЯчейки));
                 ТаблицаРезультат.Колонки[ИмяКолонки].Ширина = ?(ШиринаКолонки < ДлинаСтроки, ДлинаСтроки, ШиринаКолонки);
 
                 НоваяСтрока[ИмяКолонки] = ЗначениеЯчейки;
 
             КонецЕсли;
 
         КонецЦикла;
 
     КонецЦикла;
 
     УдалитьКолонкиСНулевойШириной(ТаблицаРезультат);
 
     // Завершение работы.
     // Закрытие Объектов.
     Попытка
         Book.Close();
     Исключение
     КонецПопытки;
     Попытка
         EXCELApplication.Application.Quit();
     Исключение
     КонецПопытки;
     EXCELApplication = Неопределено;
 
     Возврат ТаблицаРезультат;
 
 КонецФункции
 
 // Функция осуществляет экспорт изображения во внешний графический файл.
  //
  // Параметры:
  //      EXCELApplication - Объект типа "EXCEL.Application".
  //      Sheet - Обект типа "Лист книги EXCEL".
  //      НомерКолонки - Номер колонки листа.
  //      НомерСтроки - Номер строки листа.
  //      ИмяФайлаEXCEL - Короткое имя файла без расширения, из которого производится импорт.
  //      НомерЛиста - Номер листа книги EXCEL.
  //      ПравилоИмяФайлаКартинки - правило формирования имени выходного графического файла.
  //      - "УИД" (по умолчанию).
  //      - Иначе на основании имени исходного файла EXCEL, Номера листа, Номера строки, Номера колонки.
  //
  // Возвращаемые значения:
  //      ПолноеИмяФК - Полное имя графического файла.
  //
 &НаСервере
 Функция ПрочитатьКартинку_MSEXCEL(Знач EXCELApplication, Знач Sheet, Знач НомерКолонки, Знач НомерСтроки, Знач ИмяФайлаEXCEL, Знач НомерЛиста, Знач ПравилоИмяФайлаКартинки = "УИД")
     Перем GraphicObject, Chart;
     Перем ПолноеИмяФК, ФайлКартинки;
 
     Если Sheet.Shapes.Count() = 0 Тогда
         Возврат Неопределено;
     КонецЕсли;
 
     Для Каждого GraphicObject ИЗ Sheet.Shapes Цикл
         Если GraphicObject.Type = 13 И GraphicObject.TopLeftCell.Column = НомерКолонки И GraphicObject.TopLeftCell.Row = НомерСтроки Тогда
 
             // GraphicObject.Name.
             Если ПравилоИмяФайлаКартинки = "УИД" Тогда
                 ПолноеИмяФК = КаталогВременныхФайлов() + Новый УникальныйИдентификатор() + ".jpg";
             Иначе
                 ПолноеИмяФК = КаталогВременныхФайлов() + ИмяФайлаEXCEL + "Л" + НомерЛиста + "С" + НомерСтроки + "К" + НомерКолонки + ".jpg";
             КонецЕсли;
 
             Попытка
                 GraphicObject.ScaleHeight(1,1);     // Истинный размер по высоте.
                 GraphicObject.ScaleWidth(1,1);      // Истинный размер по ширине.
                 GraphicObject.Copy();
 
                 Chart = EXCELApplication.ActiveSheet.ChartObjects().Add(0, 0, GraphicObject.Width, GraphicObject.Height).Chart();
                 Chart.Paste();
                 Chart.Export(ПолноеИмяФК);
 
                 Chart = Неопределено;
 
                 ФайлКартинки = Новый Файл(ПолноеИмяФК);
                 Если ФайлКартинки.Существует() Тогда
                     Возврат ПолноеИмяФК;
                 Иначе
                     Сообщить("Не удалось экспортировать картинку из строки " + НомерСтроки + " колонки " + НомерКолонки + " в " + ПолноеИмяФК);
                     Возврат Неопределено;
                 КонецЕсли;
             Исключение
                 Сообщить(ОписаниеОшибки());
                 Сообщить("Не удалось экспортировать картинку из строки " + НомерСтроки + " колонки " + НомерКолонки + " в " + ПолноеИмяФК);
                 Возврат Неопределено;
             КонецПопытки;
 
         КонецЕсли;
     КонецЦикла;
 
     Возврат Неопределено;
 
 КонецФункции
 
 &НаСервере
 Процедура УдалитьКолонкиСНулевойШириной(ТаблицаРезультат)
     Перем МассивПустыхКолонок;
 
     // Найдем пустые колонки.
     МассивПустыхКолонок = Новый Массив;
     Для Каждого Колонка ИЗ ТаблицаРезультат.Колонки Цикл
         Если Колонка.Ширина = 0 Тогда
             МассивПустыхКолонок.Добавить(Колонка.Имя);
         КонецЕсли;
     КонецЦикла;
 
     // Удалим пустые колонки.
     Для Каждого ПустаяКолонка ИЗ МассивПустыхКолонок Цикл
         ТаблицаРезультат.Колонки.Удалить(ПустаяКолонка);
     КонецЦикла;
 
 КонецПроцедуры
 
 // Выделяет из полного имени файла имя файла без расширения.
  //
  // Параметры
  //  ПолноеИмяФайла     – Строка, содержащая имя файла, неважно с именем каталога или без.
  //
  // Возвращаемое значение:
  //   ИмяФайлаБезРасширения – короткое имя файла.
  //
 &НаСервере
 Функция ПолучитьИмяФайлаБезРасширения(ПолноеИмяФайла)
     Перем ФайлТМП, РасширениеФайла, ИмяФайлаБезРасширения;
 
     ФайлТМП = РазложитьСтрокуВМассивПодстрок(ПолноеИмяФайла, "\");
     ФайлТМП = ФайлТМП[ФайлТМП.Количество()-1];
     РасширениеФайла  = "." + ПолучитьРасширениеИмениФайла(ФайлТМП);
     ИмяФайлаБезРасширения = СтрЗаменить(ФайлТМП, РасширениеФайла, "");
 
     Возврат ИмяФайлаБезРасширения;
 
 КонецФункции
 
 // Выделяет из имени файла его расширение (набор символов после последней точки).
  //
  // Параметры
  //  ИмяФайла     – Строка, содержащая имя файла, неважно с именем каталога или без.
  //
  // Возвращаемое значение:
  //   Строка – расширение файла.
  //
 &НаСервере
 Функция ПолучитьРасширениеИмениФайла(Знач ИмяФайла)
     Перем Расширение;
 
     Расширение = ПолучитьСтрокуОтделеннойСимволом(ИмяФайла, ".");
     Возврат Расширение;
 
 КонецФункции
 
 // Удаляет кавычки с начала и конца строки, если они есть.
  //
  // Параметры:
  //  Строка - входная строка;
  //
  // Возвращаемое значение:
  //  Строка - строка без двойных кавычек.
  //
 &НаСервере
 Функция УдалитьКавычки(Знач Строка, Кавычка = """")
 
     Пока Лев(Строка, 1) = Кавычка Цикл
         Строка = Сред(Строка, 2);
     КонецЦикла;
 
     Пока Прав(Строка, 1) = Кавычка Цикл
         Строка = Лев(Строка, СтрДлина(Строка) - 1);
     КонецЦикла;
 
     Возврат Строка;
 
 КонецФункции
 
 // Удаляет из строки указанное количество символов справа.
  //
  // Параметры:
  //  Текст         - Строка - строка, в которой необходимо удалить последние символы;
  //  ЧислоСимволов - Число  - количество удаляемых символов.
  //
 &НаСервере
 Процедура УдалитьПоследнийСимволВСтроке(Текст, ЧислоСимволов)
 
     Текст = Лев(Текст, СтрДлина(Текст) - ЧислоСимволов);
 
 КонецПроцедуры
 
 // Функция "расщепляет" строку на подстроки, используя заданный
  //      разделитель. Разделитель может иметь любую длину.
  //      Если в качестве разделителя задан пробел, рядом стоящие пробелы
  //      считаются одним разделителем, а ведущие и хвостовые пробелы параметра Стр
  //      игнорируются.
  //      Например,
  //      РазложитьСтрокуВМассивПодстрок(",один,,,два", ",") возвратит массив значений из пяти элементов,
  //      три из которых - пустые строки, а
  //      РазложитьСтрокуВМассивПодстрок(" один   два", " ") возвратит массив значений из двух элементов
  //
  //  Параметры:
  //      Стр -           строка, которую необходимо разложить на подстроки.
  //                      Параметр передается по значению.
  //      Разделитель -   строка-разделитель, по умолчанию - запятая.
  //
  //  Возвращаемое значение:
  //      массив значений, элементы которого - подстроки
  //
 &НаСервере
 Функция РазложитьСтрокуВМассивПодстрок(Знач Стр, Разделитель = ",")
 
     МассивСтрок = Новый Массив();
     Если Разделитель = " " Тогда
         Стр = СокрЛП(Стр);
         Пока 1 = 1 Цикл
             Поз = Найти(Стр, Разделитель);
             Если Поз = 0 Тогда
                 МассивСтрок.Добавить(СокрЛП(Стр));
                 Возврат МассивСтрок;
             КонецЕсли;
             МассивСтрок.Добавить(СокрЛП(Лев(Стр, Поз - 1)));
             Стр = СокрЛ(Сред(Стр, Поз));
         КонецЦикла;
     Иначе
         ДлинаРазделителя = СтрДлина(Разделитель);
         Пока 1 = 1 Цикл
             Поз = Найти(Стр, Разделитель);
             Если Поз = 0 Тогда
                 Если (СокрЛП(Стр) <> "") Тогда
                     МассивСтрок.Добавить(СокрЛП(Стр));
                 КонецЕсли;
                 Возврат МассивСтрок;
             КонецЕсли;
             МассивСтрок.Добавить(СокрЛП(Лев(Стр,Поз - 1)));
             Стр = Сред(Стр, Поз + ДлинаРазделителя);
         КонецЦикла;
     КонецЕсли;
 
 КонецФункции
 
 // Функция возвращает часть строки после последнего встреченного символа в строке
 &НаСервере
 Функция ПолучитьСтрокуОтделеннойСимволом(Знач ИсходнаяСтрока, Знач СимволПоиска)
 
     ПозицияСимвола = СтрДлина(ИсходнаяСтрока);
     Пока ПозицияСимвола >= 1 Цикл
         Если Сред(ИсходнаяСтрока, ПозицияСимвола, 1) = СимволПоиска Тогда
             Возврат Сред(ИсходнаяСтрока, ПозицияСимвола + 1);
         КонецЕсли;
         ПозицияСимвола = ПозицияСимвола - 1;
     КонецЦикла;
 
     Возврат "";
 
  КонецФункции
Преимущества:
1.Метод "Microsoft EXCEL" наиболее прост в применении (кодировании).
 2. По скорости считывания находится на 2-ом месте после "Microsoft ADODB".
Особенности и Ограничения:
1. Для функционирования метода "Microsoft EXCEL" необходим установленный Microsoft Office. Коммерческий продукт.
 2. Метод может не работать в клиент-серверном варианте, если у SQL-пользователя недостаточно прав в Windows.
 3. 1-я строка файла EXCEL - строка, содержащая заголовки колонок.
 С уважением к сообществу МА!
 С уважением к сообществу МА!
Вступайте в нашу телеграмм-группу Инфостарт
