Весьма частая задача, с которой сталкивается 1С разработчик – это чтение файлов Excel и загрузка их в 1С. Есть как минимум два способа прочитать файл Excel – средствами платформы 1С, или используя COM-объект приложения MS Excel. В статье рассматривается чтение файлов xls, xlsx при помощи табличного документа.
Содержание
Общая информация
В платформе 1С 8 существует объект ТабличныйДокумент, который позволяет формировать и выводить на экран печатные формы в табличном виде. Но у табличного документа есть еще одно применение – чтение данных из табличных файлов. Поддерживаются форматы xls, xlsx и ods. Т.е. можно загружать табличные файлы, созданные в пакете MS Office или OpenOffice Calc.
Значения типа Число или Дата, содержащиеся в ячейках исходного табличного файла, можно считать двумя способами – как значение, либо как текст. Рассмотрим пример: пусть в ячейке содержится число 123,456, и установлен формат с округлением до целого числа; в этом случае отображаться будет текст “123”, а значение будет храниться 123,456
- Если прочитать с указанием способа чтения как “Значение”, в табличный документ 1С будет прочитано исходное значение 123,456
- Если прочитать с указанием способа чтения как “Текст”, значение будет потеряно, и в табличный документ прочитается текст “123”
Использование объекта ВременноеХранилище
Вспомогательные процедуры — диалог выбора файла
Следующий код не является обязательным для решения задачи – путь к исходному файлу можно указать в коде, ввести вручную, скопировать из адресной строки ОС или прочитать из БД – вариантов очень много. Мы же рассмотрим пример, когда пользователь сам указывает файл на клиентском компьютере, и путь к этому файлу помещается в реквизит. В примере будем использовать реквизит формы ПутьКФайлу
Создадим обработчик события НачалоВыбора:
&НаКлиенте
Процедура ПутьКФайлуНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
ВыбратьФайлНаКлиенте();
КонецПроцедуры
Для того чтобы код был универсальным, и работал в случае отказа от модальных синхронных методов, нам понадобится создать асинхронную процедуру ВыбратьФайлНаКлиенте(). В ней мы создаем диалог выбора для открытия файла, указываем фильтр с нужными форматами – xls и xlsx, а также отключаем множественный выбор файлов. Перед методом ВыбратьАсинх добавляем ключевое слово Ждать, с тем чтобы дальнейший код дождался возвращаемого значения.
&НаКлиенте
Асинх Процедура ВыбратьФайлНаКлиенте()
Перем Диалог;
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Диалог.Фильтр = "Excel файлы(*.xls;*.xlsx)|*.xls;*.xlsx";
Диалог.ИндексФильтра = 0;
Диалог.ПредварительныйПросмотр = Ложь;
Диалог.МножественныйВыбор = Ложь;
РезультатВыбора = Ждать Диалог.ВыбратьАсинх();
Если РезультатВыбора <> Неопределено Тогда
ПутьКФайлу = РезультатВыбора[0];
КонецЕсли;
КонецПроцедуры
Двоичные данные во временное хранилище
Логика кода будет следующая. Нам понадобятся двепроцедуры – клиентский обработчик команды, и серверный метод который и будет непосредственно считывать переданный файл.
Клиентский код:
- проверяем, указан ли путь к файлу. Если не указан – прекращаем выполнение
- Получаем двоичные данные из файла по указанному пути
- Помещаем эти двоичные данные во временное хранилище
- Далее передаем на сервер адрес этого временного хранилища
&НаКлиенте
Процедура ДвоичныеДанныеВоВременноеХранилище(Команда)
Если Не ЗначениеЗаполнено(ПутьКФайлу) Тогда
Возврат;
КонецЕсли;
ДД = Новый ДвоичныеДанные(ПутьКФайлу);
АдресВХ = ПоместитьВоВременноеХранилище(ДД);
ПрочитатьИзВХНаСервере(АдресВХ);
КонецПроцедуры
Серверный код:
- Создаем временный файл с нужным расширением (в примере – xlsx)
- Получаем двоичные данные из временного хранилища
- Записываем во временный файл
- Определяем вариант чтения файла – читать значения табличного документа как текст, или как значения
- Далее используем метод Прочитать, и считываем из временного файла данные в табличный документ
Метод Прочитать лучше делать в попытке, и отдельно продумать и написать код обработки исключения. для упрощения примера мы это исключение никак не обрабатываем. В случае, если передан поврежденный файл, или его невозможно прочитать по какой-то другой причине, он просто не считается в табличный документ.
&НаСервере
Процедура ПрочитатьИзВХНаСервере(АдресВХ, Режим = "Значение")
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xlsx");
ДД = ПолучитьИзВременногоХранилища(АдресВХ);
ДД.Записать(ИмяВременногоФайла);
Если Режим = "Текст" Тогда
СпособЧтения = СпособЧтенияЗначенийТабличногоДокумента.Текст;
Иначе
СпособЧтения = СпособЧтенияЗначенийТабличногоДокумента.Значение;
КонецЕсли;
Попытка
ТабДок.Прочитать(ИмяВременногоФайла, СпособЧтения);
Исключение
КонецПопытки;
КонецПроцедуры
Рассмотренный пример является достаточно универсальным – процедуру ПрочитатьИзВХНаСервере() можно использовать с любыми двоичными данными, помещенными во временное хранилище. Это могут быть двоичные данные, полученные с веб-сервиса, считанные из базы данных, полученные из макета, созданного в конфигураторе – код от этого не изменится.
Помещение файла на сервер в 1С
Более простой, но менее универсальный способ, предназначенный исключительно для передачи файла с клиента на сервер – это использование метода НачатьПомещениеФайлаНаСервер. В платформе предусмотрено несколько методов для помещения файлов – как одиночных, так и нескольких одновременно. Эти методы делятся на синхронные и асинхронные. Начиная с версии 8.3.18 появились методы, использующие ключевые слова Асинх и Ждать. Аналогичный метод мы рассмотрели при работе с диалогом. Далее разберем “классический” вариант с обработкой оповещения.
Логика кода следующая:
- Создаем описание оповещения и указываем в нем процедуру, которая будет вызвана после окончания помещения файла на сервер
- Указываем параметры диалога выбора файла и добавляем фильтр
- Вызываем помещение файла на сервер
- После того как файл помещен во временное хранилище, используем ту же процедуру, которую мы реализовали в первом примере – ПрочитатьИзВХНаСервере. В этом примере мы для разнообразия используем способ чтения значений как “Текст”.
&НаКлиенте
Процедура ПередачаФайла(Команда)
ОбработкаОкончанияПомещения = Новый ОписаниеОповещения("ОбработчикОкончанияПомещения", ЭтотОбъект);
ПараметрыДиалога = Новый ПараметрыДиалогаПомещенияФайлов;
ПараметрыДиалога.Фильтр = "Excel файлы(*.xls;*.xlsx)|*.xls;*.xlsx";
НачатьПомещениеФайлаНаСервер(ОбработкаОкончанияПомещения, , , АдресВХ, ПараметрыДиалога, ЭтотОбъект.УникальныйИдентификатор);
КонецПроцедуры
&НаКлиенте
Процедура ОбработчикОкончанияПомещения(ОписаниеПомещенногоФайла, ДополнительныеПараметры) Экспорт
АдресФайла = ОписаниеПомещенногоФайла.Адрес;
ПрочитатьИзВХНаСервере(АдресФайла, "Текст");
КонецПроцедуры
Использование потока для чтения файла
В случае, если нам нужно просто передать файл с клиента на сервер для сохранения в базу данных, либо мы хотим прочитать файл в формате ods(Open Documents Spreadsheet) или mxl(встроенный формат табличных документов 1С), мы можем воспользоваться еще одним способом – с использованием потоков данных.
В этом случае нам не понадобится создавать временный файл и следить за его корректным удалением. Код будет очень похож на прерыдущий пример. Мы также выбираем файл с использованием метода НачатьПомещениеФайлаНаСервер, но указываем другой фильтр. А в обработчике оповещения вызываем серверную процедуру ПрочитатьВПоток. В методе Прочитать() нам нужно явным образом указать тип файла табличного документа, который мы считываем.
&НаКлиенте
Процедура ПрочитатьЧерезПоток(Команда)
ОбработкаОкончанияПомещения = Новый ОписаниеОповещения("ОбработчикОкончанияПомещенияПоток", ЭтотОбъект);
ПараметрыДиалога = Новый ПараметрыДиалогаПомещенияФайлов;
ПараметрыДиалога.Фильтр = "файлы ODS или MXL|*.ods;*.mxl";
НачатьПомещениеФайлаНаСервер(ОбработкаОкончанияПомещения, , , АдресВХ, ПараметрыДиалога, ЭтотОбъект.УникальныйИдентификатор);
КонецПроцедуры
&НаКлиенте
Процедура ОбработчикОкончанияПомещенияПоток(ОписаниеПомещенногоФайла, ДополнительныеПараметры) Экспорт
АдресФайла = ОписаниеПомещенногоФайла.Адрес;
ПрочитатьВПоток(АдресФайла);
КонецПроцедуры
&НаСервере
Процедура ПрочитатьВПоток(АдресФайла)
ДД = ПолучитьИзВременногоХранилища(АдресФайла);
Поток = ДД.ОткрытьПотокДляЧтения();
ТабДок.Прочитать(Поток,,ТипФайлаТабличногоДокумента.ODS);
Поток.Закрыть();
КонецПроцедуры
Надеюсь, рассмотренные примеры помогут вам справиться с задачей передать файл с клиента на сервере и прочитать файл Excel в 1С.
08.11.12 — 14:10
Здравствуйте! Подскажите что может быть, ситуация следующая.
Есть сервер, на нем крутится 1С.
Есть база в которую идет загрузка из 1С(КС вариант).
Так вот при передачи фала EXCEL с клиента на сервер происходит сохранение данного файла в определенной папке(в контексте сервера), потом так же в контексте сервера происходит попытка открытия этого файла — но вылетает ошибка :
————————————————-
{Документ.КонкурсПоУслугам.Форма.ФормаЗагрузкиИзEXCEL.Форма(36)}: Ошибка при вызове метода контекста (Open)
Книга = Эксель.WorkBooks.Open(ИмяФайла);
по причине:
Произошла исключительная ситуация (Microsoft Excel): Приложению Microsoft Excel не удается получить доступ к файлу «G:1C_TempШахматка_08_11_2012_02_06_32.xlsx». Это может быть вызвано одной из следующих причин.
• Указан несуществующий файл или путь.
• Файл используется другой программой.
• Имя книги, которую вы пытаетесь сохранить, совпадает с именем другой книги, открытой в данный момент.
————————————————-
Код который все это делает ниже:
————————————————-
//2. Получим файлик для загрузки из временного хранилища
ИмяФайла = «G:1C_TempШахматка_»+Формат(ТекущаяДата(),»ДФ=dd_MM_yyyy_hh_mm_ss»)+».xlsx»;//Сисадмины сказали что в темпе хранит не феншуйно и выделили отдельную папку
Файлик = ПолучитьИзВременногоХранилища(АдресВовременномХранилище);
Файлик.Записать(ИмяФайла);
//3. Попробуем открыть EXCEL
Попытка Эксель = Новый COMОбъект(«Excel.Application»);
Исключение Сообщить(ОписаниеОшибки()); УдалитьФайлы(ИмяФайла); Возврат Неопределено;
КонецПопытки;
————————————————-
Перед открытием файлика, в режиме отладки, проверял — он существует(ФС.Существует()). Другой программой он не используется так как создается. у пользователя под которым выполняется код на стороне сервера разрешение на чтение/запись файла есть.
Что может быть, куда копать?
1 — 08.11.12 — 14:14
файл не успевает сохраниться?
2 — 08.11.12 — 14:16
выложил не весь код.Вот весь:
//2. Получим файлик для загрузки из временного хранилища
ИмяФайла = «G:1C_TempШахматка_»+Формат(ТекущаяДата(),»ДФ=dd_MM_yyyy_hh_mm_ss»)+».xlsx»;//Сисадмины сказали что в темпе хранит не феншуйно и выделили отдельную папку
Файлик = ПолучитьИзВременногоХранилища(АдресВовременномХранилище);
Файлик.Записать(ИмяФайла);
//3. Попробуем открыть EXCEL
Попытка Эксель = Новый COMОбъект(«Excel.Application»);
Исключение Сообщить(ОписаниеОшибки()); УдалитьФайлы(ИмяФайла); Возврат Неопределено;
КонецПопытки;
//4. Откроем файлик и книгу
Книга = Эксель.WorkBooks.Open(ИмяФайла);
Лист = Книга.WorkSheets(НомерЛиста);
(1) если бы.Ставил точку останова на
Книга = Эксель.WorkBooks.Open(ИмяФайла);
находил этот файлик по ИмяФайла, открывал его, закрывал и продолжал откладку.Все равно куй.
3 — 08.11.12 — 14:17
(0) Почему-то напрашивается конструкция типа Файлик.Закрыть() после записи:)
Файлик что за тип?
Может стоит после записи обнулить эту переменную
4 — 08.11.12 — 14:18
кстате — а нафик передавать через хранилище файл, если достаточно безконтекстный вызов сервера с передачей имени файла?
5 — 08.11.12 — 14:18
+4 а по имени уже открывать
6 — 08.11.12 — 14:19
попробуй что бы все это делалось под админскими правами
7 — 08.11.12 — 14:21
ах да проверь у тебя данные есть в ИмяФайла
8 — 08.11.12 — 14:25
(4) может я чего то не понял, но файл находится на стороне клиента — это один пользователь, сервер крутится на другом компе — это другой пользователь. Т.е. файл при вызове сервера находится вообще на другом компе, в нешаренной папке. Если я что то непонимаю — попраавте.
(3)Файл — xlsx(EXCEL).Закрыть не получится, потому что
Файлик = ПолучитьИзВременногоХранилища(АдресВовременномХранилище);
Передает двоичные данные. Файлик — это двоичные данные.Название просто у него такое
(6) Если бы я мог под админскими правами проверить, организация большая — я в дочке. Пока прав допросишся пол года пройдет. Но на файл, после того как он создался но еще не прочитался(точка останова на Книга = Эксель.WorkBooks.Open(ИмяФайла)) я давал полные права всем.
в имени файла — имя фала. По РДП цепляюсь на сервер, ввожу в строку обозревателя то что там находится — открывается мой файл.
9 — 08.11.12 — 14:27
Кстати, еще одна закономерность. Выгрузил базу. Развернул на сервере в файловом варианте — все работает.
10 — 08.11.12 — 14:28
(8) я в том плане, что после записи, система считает что этот файл открыт одинэсиной. Попробуй просто прописать Файлик = «» после записи.
11 — 08.11.12 — 14:28
т.е. в ИмяФайла название твоего файла и путь, теперь проверь есть ли у тебя права на его чтение
12 — 08.11.12 — 14:30
(9) тогда не (9). А если файлик на сервер вручную бросить и попробовать открыть через 1С на сервере? открывает?
13 — 08.11.12 — 14:31
(11) у меня права есть на него.Я его открываю. У пользователя под которым выполняются серверные процедуры я не знаю есть права или нет. Но с одной стороны он этот файл записывает, значит наверное и читать может. Кроме того перед тем как файл будет прочитан я на него даю полные права(Мой файл-сфойства-безопасность-Группы и пользователи + все(чтение/запись))
14 — 08.11.12 — 14:31
(12) — отличная мысл.Чет сам не допер.Ша попробую
15 — 08.11.12 — 14:31
G:1C_Temp Это локальный путь на сервере или подключённый сетевой диск на клиенте? Мож перепутал вызовы и на клиенте файл экселя пытаешься открыть?
16 — 08.11.12 — 14:35
(15) — локальный путь. Диск G физически висит на сервере
17 — 08.11.12 — 14:39
(12) не сработало. Давайте код выложу.Может где накосячил. А то право неловко — такая ерунда а уже часа 3 мозг себе ипу этим.
(15), кстати сейчас что бы избежать этой ошибки запуская 1С предприятие по РДП на сервере. Т.е. и клиент и сервер один и тот же комп, путаници с дисками быть не должно. Кроме того файл проверя в режиме отладки на стороне сервера — он существет(ФС = новый Файл(ИмяИмяФайла); ФС.Существует())
18 — 08.11.12 — 14:39
(16) Перепутал вызовы, открываешь эксель на клиенте.
Не хватает каких то прав на сервере.
Версия экселя не подходит.
Наоткрывал кучу КОМ объеков, они все в памяти сидят и не могут решить чей это файл С открытием экселя часто такая фигня. При какой то ошибке 1С эксель остаётся висеть в памяти. Открой диспечер задач на серваке и погляди.
19 — 08.11.12 — 14:39
Вызов на стороне клиента:
&НаКлиенте
Процедура Загрузить(Команда)
//1. Поместим наш файлик во временное хранилище
Перем АдресВовременномХранилище;
Если Не ЗначениеЗаполнено(Файл) Тогда Возврат; КонецЕсли;
ПоместитьФайл(АдресВовременномХранилище, Файл, , Ложь);
//2. Произведем чтение и разбор этого файла
Адрес = ПроизвестиЧтениеГоризонтальнойШахматки(АдресВовременномХранилище);
//3. Оповестим о том что все сделано
Если ЭтоАдресВременногоХранилища(Адрес) Тогда
ОповеститьОВыборе(Новый Структура(«ДанныеЗагрузки», Адрес));
Иначе
ЭтаФорма.Закрыть();
КонецЕсли;
КонецПроцедуры
20 — 08.11.12 — 14:41
Вызов на стороне сервера:
&НаСервере
Функция ПроизвестиЧтениеГоризонтальнойШахматки(АдресВовременномХранилище)
//1. Сформируем табличку в которую будем загружать
тзУслуги = Новый ТаблицаЗначений;
тзУслуги.Колонки.Добавить(«Лот» , Новый ОписаниеТипов(«СправочникСсылка.Объекты»));
тзУслуги.Колонки.Добавить(«Услуга» , Новый ОписаниеТипов(«СправочникСсылка.Объекты»));
тзУслуги.Колонки.Добавить(«Марка» , Новый ОписаниеТипов(«Строка»));
тзУслуги.Колонки.Добавить(«ЕдиницаИзмерения», Новый ОписаниеТипов(«СправочникСсылка.ЕдиницыИзмерения»));
тзУслуги.Колонки.Добавить(«Количество» , Новый ОписаниеТипов(«Число»));
тзУслуги.Колонки.Добавить(«ПДЦБезНДС» , Новый ОписаниеТипов(«Число»));
тзУслуги.Колонки.Добавить(«ПДЦ» , Новый ОписаниеТипов(«Число»));
тзУслуги.Колонки.Добавить(«Дорога» , Новый ОписаниеТипов(«СправочникСсылка.Дороги»));
тзУслуги.Колонки.Добавить(«УчастникКонкурса», Новый ОписаниеТипов(«СправочникСсылка.Организации»));
тзУслуги.Колонки.Добавить(«ФКП» , Новый ОписаниеТипов(«Число»));
тзУслуги.Колонки.Добавить(«ФКП_БезНДС» , Новый ОписаниеТипов(«Число»));
//2. Получим файлик для загрузки из временного хранилища
//ИмяФайла = «G:1C_TempШахматка_»+Формат(ТекущаяДата(),»ДФ=dd_MM_yyyy_hh_mm_ss»)+».xlsx»;//Сисадмины сказали что в темпе хранит не феншуйно и выделили отдельную папку
ИмяФайла = «G:1С ОбработкиШахматка.xlsx»;
Файлик = ПолучитьИзВременногоХранилища(АдресВовременномХранилище);
Файлик.Записать(ИмяФайла);
Файлик = «»;
//3. Попробуем открыть EXCEL
Попытка Эксель = Новый COMОбъект(«Excel.Application»);
Исключение Сообщить(ОписаниеОшибки()); УдалитьФайлы(ИмяФайла); Возврат Неопределено;
КонецПопытки;
//4. Откроем файлик и книгу
Книга = Эксель.WorkBooks.Open(ИмяФайла);
Лист = Книга.WorkSheets(НомерЛиста);
//5. Получим количество колонок и строк
ВсегоКолонок = Лист.Cells(1,1).SpecialCells(11).Column;
ВсегоСтрок = Лист.Cells(1,1).SpecialCells(11).Row;
//Далше всякая ерунда, она не нужна что бы глаз не мозолить
КонецФункции
21 — 08.11.12 — 14:43
Ну, как, я и говорил. В исключении не обнуляется Эксель. Этих экселей у тебя на сервере уже с пол сотни открыо. И все жаждут файла Шахматка.xlsx
22 — 08.11.12 — 14:45
(21) :/, млять. они под другим пользователем висят. У меня прав нет что бы смотреть процессы других пользователей
23 — 08.11.12 — 14:46
(22) Отладку то под своим надо делать.
24 — 08.11.12 — 14:48
(23) не понял. Вызов экселя идет в контексте сервера, т.е. от имени пользователя под которым стартанула служба агента серверов. А это не я, это другой пользователь. Под ним возможно и висят зомби эксели. Ша буду админов теребить
25 — 08.11.12 — 14:48
+21 Я обычно дополнительно закрываю эксель при закрытии формы. Чтоб уж наверняка его прибить. И то эта ска каким то образом иногда умудряется выживать.
26 — 08.11.12 — 14:52
Файлик=Неоределено;
27 — 08.11.12 — 14:59
Что вы к Файлику прикопались. Это двоичные данные, это не эксел.
(21) админы говорят что процессов по экселю нет ни под кем. человеки. Мож я скину кому cf с одним этим документом, кто нить глянте в КС варианте у себя, а?
28 — 08.11.12 — 14:59
>>> «У пользователя под которым выполняются серверные процедуры»
Ну все… если у вас голубчик стоит серверная версия 8-ки, то то-что выполняется на сервере, выполняется под серверным пользователем «Локальным относительно сервера».
А вообще, телепат устал, так что…
29 — 08.11.12 — 15:00
(27)Он рабочий… а вот у вас смутное представление о работе сервера 1С.
А у нас нехватка данных , для того что бы вас послать в правильном пути
30 — 08.11.12 — 15:01
(28,27) какие данные нужны?
31 — 08.11.12 — 15:03
32 — 08.11.12 — 15:07
(31), спасибо, хоть что то.Шас буду смотреть
33 — 08.11.12 — 15:07
(30) я всё-таки за (1) Поэтому лучше так
//3. Попробуем открыть EXCEL
Попытка Эксель = Новый COMОбъект(«Excel.Application»);
Исключение Сообщить(ОписаниеОшибки()); УдалитьФайлы(ИмяФайла); Возврат Неопределено;
КонецПопытки;
Файлик = ПолучитьИзВременногоХранилища(АдресВовременномХранилище);
Файлик.Записать(ИмяФайла);
34 — 08.11.12 — 15:12
(30)КтоЗдесь?
(32)Не заработает
35 — 08.11.12 — 15:15
(33) сделал даже так:
//3. Попробуем открыть EXCEL
Попытка Эксель = Новый COMОбъект(«Excel.Application»);
Исключение Сообщить(ОписаниеОшибки());
//УдалитьФайлы(ИмяФайла);
Эксель = Неопределено;
Возврат Неопределено;
КонецПопытки;
НачальноеВремя = ТекущаяДата();
Пока ТекущаяДата()< НачальноеВремя + 5 Цикл КонецЦикла;
//2. Получим файлик для загрузки из временного хранилища
ИмяФайла = «G:1C_TempШахматка_»+Формат(ТекущаяДата(),»ДФ=dd_MM_yyyy_hh_mm_ss»)+».xlsx»;//Сисадмины сказали что в темпе хранит не феншуйно и выделили отдельную папку
Файлик = ПолучитьИзВременногоХранилища(АдресВовременномХранилище);
Файлик.Записать(ИмяФайла);
//4. Откроем файлик и книгу
Книга = Эксель.WorkBooks.Open(ИмяФайла);
Лист = Книга.WorkSheets(НомерЛиста);
все равно не работает, та же ошибка.
36 — 08.11.12 — 15:16
На сервере с помошью
WshNetwork = Новый COMОбъект(«WScript.Network»);
ПодКемСеанс = WshNetwork.UserName;
Проверил под кем работа. Работа идет под доменным администратором
37 — 08.11.12 — 15:16
(35) Пистят твои админы. Если Эксель не закрывался, то куда он мог деться?
38 — 08.11.12 — 15:20
(37) может и пистят. Но объясните мне тогда, почему все отрабатывает если я на сервере(под рдп) работаю с фаловой копией этой базы? Все таки какая то куйня получается с доменным админом под которым работает сервер 1с? Или я, как сказал 29, смутно представляю работу сервера 1с?
Serginio1
39 — 08.11.12 — 15:31
(38) Прочитай ветку в 31 и разберись с правами DCOM
Excel — это сторонняя программа, ее можно запускать из 1С в невидимом и видимом режиме и пользоваться всеми возможностями. Excel должен быть установлен на компьютере. Для примера приведено чтение таблицы в из файла Excel на клиенте, передача на сервер и создание на сервере таблицы значений с данными из файла. Такую задачку любят давать на собеседованиях на должность программиста 1С.
&НаКлиенте
Процедура НажатиеКноки()
// обращаемся к Excel
Попытка
Эксель = новый COMОбъект(«Excel.Application»);
Исключение
Сообщить(ОписаниеОшибки());
Возврат;
КонецПопытки;
ПутьКФайлу = «C:Некоторый файл.xlsx»;
// открываем ексель файл
Книга = Эксель.WorkBooks.Open(ПутьКФайлу);
// переходим на первую страницу
Лист = Книга.WorkSheets(1);
// для количества колонок и строк в экселе есть специальные ячейки
ВсегоКолонок = Лист.Cells(1,1).SpecialCells(11).Column;
ВсегоСтрок = Лист.Cells(1,1).SpecialCells(11).Row;
// сохраняем файл в массив строк, где строка это так же массив (на клиенте
// нельзя создавать таблицу значений
НаборСтрокФайла = новый массив;
для Строка = 1 по ВсегоСтрок цикл
МассивСтрока = новый массив;
для Колонка = 1 по ВсегоКолонок цикл
// получаем значение из ячейки excel
Значение = СокрЛП(Лист.Cells(Строка,Колонка).Value);
МассивСтрока.Добавить(Значение);
КонецЦикла;
НаборСтрокФайла.Добавить(МассивСтрока);
КонецЦикла;
// запишем файл с другим именем
Эксель.SaveAs(«C:ФайлСДругимИменем.xlsx»);
// закрываем ексель, иначе он останется висеть в памяти
Эксель.Application.Quit();
КонецПроцедуры
&НаСервере
Процедура СоздатьИОбработатьТаблицуЗначений(НаборСтрокФайла, ВсегоКолонок)
ТЗ = новый ТаблицаЗначений;
// создаем колонки таблицы значений (столько сколько в файле ексель)
для й=1 по ВсегоКолонок цикл
ТЗ.Колонки.Добавить(«кол» + Формат(й,«ЧЦ=4; ЧГ=»));
КонецЦикла;
// переносим строки из массива в таблицу значений
для каждого МассивСтрока из НаборСтрокФайлацикл
НовСтрока = ТЗ.Добавить();
для Колонка = 1 по ВсегоКолонок цикл
// переносим значение из массива в таблицу
НовСтрока[Колонка — 1] = МассивСтрока[Колонка — 1];
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Далее приводятся наиболее частые ситуации, возникающие на
Поиск и замена текста в ячейках файла Excel
//Выбираем область поиска — весь лист
ОбластьПоиска = Лист.Cells;
// Начинаем поиск с левого верхнего угла
НачалоЛиста =Лист.Cells(1, 1);
// Ищем ячейку с текстом «привет»
ОбластьПараметр = ОбластьПоиска.Find(«привет», НачалоЛиста);
// Если нашли вывсодим найденую строку
Если ОбластьПараметр <> неопределено Тогда
Сообщить(ОбластьПараметр.Value);
КонецЕсли;
Работа со строками в Excel
//Выбираем первую строку
НачальнаяСтрока = Лист.Cells(1, 1);
// Выделяем всю строку
НачальнаяСтрока .EntireRow.Select();
// Копируем выделенное
НачальнаяСтрока .EntireRow.Copy();
// Вставляем (новая строка будет вставлена тут же)
НачальнаяСтрока .EntireRow.Insert();
// Удалим строку
НачальнаяСтрока .EntireRow.Delete();
Прочие полезные методы Excel
Эксель.Visible = Видимость; | 0 — Excel не виден, 1 — виден. |
Книга = Эксель.WorkBooks.Add(); | Создание новой книги (файла) Excel. |
Книга.SaveAs(ИмяФайла); | Сохранение книги Excel. |
Лист = Книга.WorkSheets.Add(); | Добавление нового листа в книгу. |
Книга = Эксель.WorkBooks.Open(ИмяФайла); | Открытие существующей книги (файла) Excel. |
Лист = Книга.WorkSheets(НомерЛиста); | Установка листа в качестве рабочего с номером НомерЛиста. |
Лист.Name = ИмяЛиста; | Задание рабочему листу имени ИмяЛиста |
Лист.PageSetup.Zoom = Масштаб; | Задание параметра страницы «Масштаб» (от 10 до 400). |
Лист.PageSetup.Orientation = Ориентация; | Ориентация: 1 — книжная, 2 — альбомная. |
Лист.PageSetup.LeftMargin = Эксель.CentimetersToPoints(Сантиметры); | Задание левой границы (в сантиметрах). |
Лист.PageSetup.TopMargin = Эксель.CentimetersToPoints(Сантиметры); | Задание верхней границы (в сантиметрах). |
Лист.PageSetup.RightMargin = Эксель.CentimetersToPoints(Сантиметры); | Задание правой границы (в сантиметрах). |
Лист.PageSetup.BottomMargin = Эксель.CentimetersToPoints(Сантиметры); | Задание нижней границы (в сантиметрах). |
Лист.Columns(НомерКолонки).ColumnWidth = Ширина; | Задание ширины колонке. |
Лист.Cells(НомерСтроки, НомерКолонки).Value = Значение; | Ввод данных в ячейку. |
Лист.Cells(НомерСтроки,НомерКолонки).Font.Name = ИмяШрифта; | Установка шрифта в ячейке. |
Лист.Cells(НомерСтроки,НомерКолонки).Font.Size = РазмерШрифта; | Установка размера шрифта в ячейке. |
Лист.Cells(НомерСтроки,НомерКолонки).Font.Bold = Жирный; | 1 — жирный шрифт, 0 — нормальный. |
Лист.Cells(НомерСтроки,НомерКолонки).Font.Italic = Курсив; | 1 — наклонный шрифт, 0 — нормальный. |
Лист.Cells(НомерСтроки,НомерКолонки).Font.Underline = Подчеркнутый; | 2 — подчеркнутый, 1 — нет. |
Лист.Cells(НомерСтроки, НомерКолонки).NumberFormat = Формат; | Установка формата данных ячейки. |
Лист.Cells(НомерСтроки,НомерКолонки).Borders.Linestyle = ТипЛинии; | Установка рамок ячейки. 1 — тонкая сплошная. |
Лист.Protect(); | Установка защиты на лист |
Лист.UnProtect(); | Снятие защиты с листа |
Лист.Cells(Строка, Столбец).Locked=0; | Ячейка будет доступной (и после установки защиты на лист) |
Эксель.DisplayAlerts = False; | Убрать все сообщение при открытии файла. Сообщения останавливают выполнения кода до реакции пользователя |
Исходная задача: в файле хранится список контрагентов со следующей информацией:
- наименование
- полное наименование
- УНП
Нужно прочитать данные из этого файла для последующей загрузки в 1С в справочник «Контрагенты». В этой статье не будем затрагивать вопрос создания контрагентов в справочнике, рассмотрим только процесс чтения данных из файла Excel.
Прочитать файл Excel в 1С можно с помощью объекта встроенного языка ТабличныйДокумент. Ниже приведен фрагмент программного кода, который решает эту задачу:
————————————————————————————-
ТабДок = Новый ТабличныйДокумент;
//путь к файлу, который нужно прочитать
ПутьКФайлу = «C:tempСписокКонтрагентов.xls»;
//чтение файла, используя метод Прочитать (ВАЖНО: метод доступен только на сервере)
Попытка
ТабДок.Прочитать(ПутьКФайлу, СпособЧтенияЗначенийТабличногоДокумента.Значение);
Исключение
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = «Не удалось прочитать указанный файл по причине: » + ОписаниеОшибки();
Сообщение.Сообщить();
Возврат;
КонецПопытки;
//получение количества строк в таблице
КоличествоСтрок = ТабДок.ВысотаТаблицы;
//создание таблицы, в которую будут помещены данные из файла
ДанныеФайла = Новый ТаблицаЗначений;
ДанныеФайла.Колонки.Вставить(«Наименование»);
ДанныеФайла.Колонки.Вставить(«ПолноеНаименование»);
ДанныеФайла.Колонки.Вставить(«УНП»);
//чтение данных таблицы по ячейкам
Для НомерСтроки = 2 По КоличествоСтрок Цикл
СтрокаДанных = ДанныеФайла.Добавить();
//получение данных ячейки с адресом R<НомерСтроки>C<НомерКолонки> (пример: R1C2)
СтрокаДанных.Наименование = ТабДок.ПолучитьОбласть(«R» + Формат(НомерСтроки, «ЧГ=0») + «C» + 1).ТекущаяОбласть.Текст;
СтрокаДанных.ПолноеНаименование = ТабДок.ПолучитьОбласть(«R» + Формат(НомерСтроки, «ЧГ=0») + «C» + 2).ТекущаяОбласть.Текст;
СтрокаДанных.УНП = ТабДок.ПолучитьОбласть(«R» + Формат(НомерСтроки, «ЧГ=0») + «C» + 3).ТекущаяОбласть.Текст;
КонецЦикла;
————————————————————————————-
Примечание: метод «Прочитать()» объекта ТабличныйДокумент доступен только на сервере. Поэтому чтение данных описанным способом возможно только на стороне сервера.
Ставьте + в комментариях, если Вам помогла эта статья 🙂
2019-12-16 15:42
Программирование
На чтение 9 мин Просмотров 26.4к. Опубликовано 09.11.2017
MS Excel давно стал стандартом для работы с электронными таблицами. В статье рассматриваются способы программной выгрузки и загрузки из 1С в файлы Excel.
Существует несколько способов программной работы с файлами Excel из 1С. Каждый из них имеет свои преимущества и недостатки.
Содержание
- Обмен через табличный документ
- Обмен через OLE
- Использование COMSafeArray
- Обмен через ADO
- Выгрузка без программирования
Обмен через табличный документ
Данный способ простой. Его суть заключается в том, что объект ТабличныйДокумент имеет методы:
- Записать(<ИмяФайла>, <ТипФайлаТаблицы>) для выгрузки данных в файл;
- Прочитать(<ИмяФайла>, <СпособЧтенияЗначений>) для загрузки данных из файла.
Внимание!
Метод Записать() доступен как на клиенте, так и на сервере. Метод Прочитать() доступен только на стороне сервера. Необходимо помнить об этом
при планировании клиент-серверного взаимодействия.
Рассмотрим пример сохранения табличного документа в файл. Необходимо любым способом создать и заполнить объект ТабличныйДокумент, а выгрузка в файл осуществляется всего лишь одной строкой:
ТабДок.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.XLSX);
Здесь ТабДок — сформированный табличный документ, ПутьКФайлу — имя файла для выгрузки, ТипФайлаТабличногоДокумента.XLSX — формат создаваемого файла. Поддерживаются следующие форматы Excel:
- XLS95 — формат Excel 95;
- XLS97 — формат Excel 97;
- XLSX — формат Excel 2007.
Загрузка из файла осуществляется также достаточно просто:
ТабДок = Новый ТабличныйДокумент;
ТабДок.Прочитать(ПутьКФайлу, СпособЧтенияЗначенийТабличногоДокумента.Значение);
Здесь ПутьКФайлу — путь к загружаемому файлу Excel. СпособЧтенияЗначенийТабличногоДокумента.Значение определяет, каким образом нужно интерпретировать данные, считываемые из исходного документа. Доступны варианты:
- Значение;
- Текст.
Обмен через OLE
Обмен через технологию OLE automation, пожалуй, самый распространенный вариант программной работы с файлами Excel. Он позволяет использовать весь функционал, предоставляемый Excel, но отличается медленной скоростью работы по сравнению с другими способами. Для обмена через OLE требуется установка MS Excel:
- На компьютере конечного пользователя, если обмен происходит на стороне клиента;
- На компьютере сервера 1С:Предприятие, если обмен происходит на стороне сервера.
Пример выгрузки:
// Создание COM-объекта
Эксель = Новый COMОбъект(«Excel.Application»);
// Отключение вывода предупреждений и вопросов
Эксель.DisplayAlerts = Ложь;
// Создание новой книги
Книга = Эксель.WorkBooks.Add();
// Позиционирование на первом листе
Лист = Книга.Worksheets(1);// Запись значения в ячейку
Лист.Cells(НомерСтроки, НомерКолонки).Value = ЗначениеЯчейки;// Сохранение файла
Книга.SaveAs(ИмяФайла);// Закрытие Эксель и освобождение памяти
Эксель.Quit();
Эксель = 0;
Примеры чтения:
// —— ВАРИАНТ 1 ——
// Создание COM-объекта
Эксель = Новый COMОбъект(«Excel.Application»);
// Открытие книги
Книга = Эксель.Workbooks.Open(ПутьКФайлу);
// Позиционирование на нужном листе
Лист = Книга.Worksheets(1);// Чтение значения ячейки, обычно здесь располагается цикл обхода ячеек
ЗначениеЯчейки = Лист.Cells(НомерСтроки, НомерКолонки).Value;// Закрытие книги
Книга.Close(0);// Закрытие Эксель и освобождение памяти
Эксель.Quit();
Эксель = 0;// —— ВАРИАНТ 2 ——
// Открытие книги
Книга = ПолучитьCOMОбъект(ПутьКФайлу);
// Позиционирование на нужном листе
Лист = Книга.Worksheets(1);// Чтение значения ячейки, обычно здесь располагается цикл обхода ячеек
ЗначениеЯчейки = Лист.Cells(НомерСтроки, НомерКолонки).Value;// Закрытие книги
Книга.Application.Quit();
Для обхода всех заполненных строк листа Excel можно использовать следующие приемы:
// —— ВАРИАНТ 1 ——
КоличествоСтрок = Лист.Cells(1, 1).SpecialCells(11).Row;
Для НомерСтроки = 1 По КоличествоСтрок Цикл
ЗначениеЯчейки = Лист.Cells(НомерСтроки, НомерКолонки).Value;
КонецЦикла;// —— ВАРИАНТ 2 ——
НомерСтроки = 0;
Пока Истина Цикл
НомерСтроки = НомерСтроки + 1;
ЗначениеЯчейки = Лист.Cells(НомерСтроки, НомерКолонки).Value;
Если НЕ ЗначениеЗаполнено(ЗначениеЯчейки) Тогда
Прервать;
КонецЕсли;
КонецЦикла;
Вместо последовательного обхода всех строк листа можно выгрузить все данные в массив и работать с ним. Такой подход будет быстрее при чтении большого объема данных:
ВсегоКолонок = Лист.Cells(1, 1).SpecialCells(11).Column;
ВсегоСтрок = Лист.Cells(1, 1).SpecialCells(11).Row;Область = Лист.Range(Лист.Cells(1, 1), Лист.Cells(ВсегоСтрок, ВсегоКолонок));
Данные = Область.Value.Выгрузить();
В таблице ниже приведены наиболее востребованные свойства и методы для работы с Excel через OLE:
Действие | Код | Комментарий |
Работа с приложением | ||
Установка видимости окна приложения | Эксель.Visible = Ложь; | |
Установка режима вывода предупреждений (выводить/не выводить) | Эксель.DisplayAlerts = Ложь; | |
Закрытие приложения | Эксель.Quit(); | |
Работа с книгой | ||
Создание новой книги | Книга = Эксель.WorkBooks.Add(); | |
Открытие существующей книги | Книга = Эксель.WorkBooks.Open(ИмяФайла); | |
Сохранение книги | Книга.SaveAs(ИмяФайла); | |
Закрытие книги | Книга.Close(0); | |
Работа с листом | ||
Установка текущего листа | Лист = Книга.WorkSheets(НомерЛиста); | |
Установка имени | Лист.Name = Имя; | |
Установка защиты | Лист.Protect(); | |
Снятие защиты | Лист.UnProtect(); | |
Установка ориентации страницы | Лист.PageSetup.Orientation = 2; | 1 — книжная, 2 — альбомная |
Установка левой границы | Лист.PageSetup.LeftMargin = Эксель.CentimetersToPoints(Сантиметры); | |
Установка верхней границы | Лист.PageSetup.TopMargin = Эксель.CentimetersToPoints(Сантиметры); | |
Установка правой границы | Лист.PageSetup.RightMargin = Эксель.CentimetersToPoints(Сантиметры); | |
Установка нижней границы | Лист.PageSetup.BottomMargin = Эксель.CentimetersToPoints(Сантиметры); | |
Работа со строками, колонками, ячейками | ||
Установка ширины колонки | Лист.Columns(НомерКолонки).ColumnWidth = Ширина; | |
Удаление строки | Лист.Rows(НомерСтроки).Delete(); | |
Удаление колонки | Лист.Columns(НомерКолонки).Delete(); | |
Удаление ячейки | Лист.Cells(НомерСтроки, НомерКолонки).Delete(); | |
Установка значения | Лист.Cells(НомерСтроки, НомерКолонки).Value = Значение; | |
Объединение ячеек | Лист.Range(Лист.Cells(НомерСтроки, НомерКолонки), Лист.Cells(НомерСтроки1, НомерКолонки1)).Merge(); | |
Установка шрифта | Лист.Cells(НомерСтроки, НомерКолонки).Font.Name = ИмяШрифта; | |
Установка размера шрифта | Лист.Cells(НомерСтроки, НомерКолонки).Font.Size = РазмерШрифта; | |
Установка жирного шрифта | Лист.Cells(НомерСтроки, НомерКолонки).Font.Bold = 1; | 1 — жирный шрифт, 0 — нормальный |
Установка курсива | Лист.Cells(НомерСтроки, НомерКолонки).Font.Italic = 1; | 1 — курсив, 0 — нормальный |
Установка подчеркнутого шрифта | Лист.Cells(НомерСтроки, НомерКолонки).Font.Underline = 2; | 2 — подчеркнутый, 1 — нет |
Для того, чтобы узнать какое свойство нужно менять или какой метод вызвать можно воспользоваться макросами Excel. Если записать макрос с требуемыми действиями, то после можно посмотреть программный код на VBA записанного макроса.
Использование COMSafeArray
При выгрузке больших объемов данных из 1С в Excel для ускорения можно использовать объект COMSafeArray. Согласно определению из синтакс-помощника, COMSafeArray — объектная оболочка над многомерным массивом SafeArray из COM. Позволяет создавать и использовать SafeArray для обмена данными между COM-объектами. Проще говоря, это массив значений, который можно использовать для обмена между приложениями по технологии OLE.
// Создание COMSafeArray
МассивКом = Новый COMSafeArray(«VT_Variant», ВсегоКолонок, ВсегоСтрок);
// Заполнение COMSafeArray
Для Стр = 0 По ВсегоСтрок — 1 Цикл
Для Кол = 0 По ВсегоКолонок — 1 Цикл
МассивКом.SetValue(Кол, Стр, Значение);
КонецЦикла;
КонецЦикла;
// Присвоение области листа Excel значений из COMSafeArray
Лист.Range(Лист.Cells(1, 1), Лист.Cells(ВсегоСтрок, ВсегоКолонок)).Value = МассивКом;
Обмен через ADO
Файл Excel при обмене через ADO представляет собой базу данных, к которой можно обращаться при помощи SQL-запросов. Установка MS Excel не требуется, но обязательно наличие драйвера ODBC, при помощи которого будет осуществляться доступ. Используемый драйвер ODBC определяется при указании строки соединения к файлу. Обычно требуемый драйвер уже установлен на компьютере.
Обмен через ADO заметно быстрее обмена через OLE, но при выгрузке нет возможности использовать функционал Excel для оформления ячеек, разметки страниц, задания формул и т.д.
Пример выгрузки:
// Создание COM-объекта для соединения
Соединение = Новый COMОбъект(«ADODB.Connection»);// Установка строки соединения
Соединение.ConnectionString = «
|Provider=Microsoft.ACE.OLEDB.12.0;
|Data Source=»+ИмяФайла+«;
|Extended Properties=»»Excel 12.0 XML;HDR=YES»»;»;
Соединение.Open(); // Открытие соединения// Создание COM-объекта для команды
Команда = Новый COMОбъект(«ADODB.Command»);
Команда.ActiveConnection = Соединение;// Присвоение текста команды для создания таблицы
Команда.CommandText = «CREATE TABLE [Лист1] (Колонка1 char(255), Колонка2 date, Колонка3 int, Колонка4 float)»;
Команда.Execute(); // Выполнение команды// Присвоение текста команды для добавления строки таблицы
Команда.CommandText = «INSERT INTO [Лист1] (Колонка1, Колонка2, Колонка3, Колонка4) values (‘абвгдеё’, ‘8/11/2017’, ‘12345’, ‘12345,6789’)»;
Команда.Execute(); // Выполнение команды// Удаление команды и закрытие соединения
Команда = Неопределено;
Соединение.Close();
Соединение = Неопределено;
Для создания нового листа и формирования его структуры можно воспользоваться объектами ADOX.Catalog и ADOX.Table. В этом случае код примет вид:
// Создание COM-объекта для работы с книгой
Книга = Новый COMОбъект(«ADOX.Catalog»);
Книга.ActiveConnection = Соединение;// Создание COM-объекта для работы со структурой данных на листе
Таблица = Новый COMОбъект(«ADOX.Table»);
Таблица.Name = «Лист1»;
Таблица.Columns.Append(«Колонка1», 202);
Таблица.Columns.Append(«Колонка2», 7);
Таблица.Columns.Append(«Колонка3», 5);
Таблица.Columns.Append(«Колонка4», 5);// Создание в книге листа с описанной структурой
Книга.Tables.Append(Таблица);
Таблица = Неопределено;
Книга = Неопределено;
В приведенном примере в методе
Таблица.Columns.Append(«Колонка1», 202);
во втором параметре указывается тип колонки. Параметр необязательный, вот некоторые значения типа колонки:
- 5 — adDouble;
- 6 — adCurrency;
- 7 — adDate;
- 11 — adBoolean;
- 202 — adVarWChar;
- 203 — adLongVarWChar.
Пример чтения:
// Создание COM-объекта для соединения
Соединение = Новый COMОбъект(«ADODB.Connection»);// Установка строки соединения
Соединение.ConnectionString = «
|Provider=Microsoft.ACE.OLEDB.12.0;
|Data Source=»+ИмяФайла+«;
|Extended Properties=»»Excel 12.0 XML;HDR=YES»»;»;
Соединение.Open(); // Открытие соединения// Создание COM-объекта для получения выборки
Выборка = Новый COMОбъект(«ADODB.Recordset»);
ТекстЗапроса = «SELECT * FROM [Лист1$]»;// Выполнение запроса
Выборка.Open(ТекстЗапроса, Соединение);// Обход результата выборки
Пока НЕ Выборка.EOF() Цикл
ЗначениеКолонки1 = Выборка.Fields.Item(«Колонка1»).Value; // Обращение по имени колонки
ЗначениеКолонки2 = Выборка.Fields.Item(0).Value; // Обращение по индексу колонки
Выборка.MoveNext();
КонецЦикла;Выборка.Close();
Выборка = Неопределено;
Соединение.Close();
Соединение = Неопределено;
В строке соединения параметр HDR определяет как будет восприниматься первая строка на листе. Возможны варианты:
- YES — первая строка воспринимается как названия колонок. К значениям можно обращаться по имени и по индексу колонки.
- NO — первая строка воспринимается как данные. К значениям можно обращаться только по индексу колонки.
В приведенных примерах рассмотрено лишь несколько объектов ADO. Объектная модель ADO состоит из следующих объектов:
- Connection;
- Command;
- Recordset;
- Record;
- Fields;
- Stream;
- Errors;
- Parameters;
- Properties.
Выгрузка без программирования
Для сохранения данных из 1С в Excel не всегда целесообразно прибегать к программированию. Если в режиме Предприятия пользователь может отобразить требуемые для выгрузки данные, то, их возможно сохранить в Excel без программирования.
Для сохранения табличного документа (например, результата отчета) можно вызвать команду Сохранить или Сохранить как… главного меню.
В открывшемся окне требуется выбрать каталог, имя и формат сохраняемого файла.
Для сохранения данных динамических списков (например, списка номенклатуры) необходимо:
- Вывести данные в табличный документ при помощи команды Еще ⇒ Вывести список…;
- Сохранить табличный документ в требуемый формат.