13.11.15 — 09:18
Есть лист эксель, хранится на рабочем столе(в нем выгрузка для документа поступления). Необходимо загрузить этот файлик т.е. программно открыть, передать на сервер и обработать.Проблема в том, что на севере Excell не установлен и установка запрещена. Таким образом файлик excell разбираем на клиенте и в каком то формате необходимо передать на сервер. Как Вы уже догадались реализация на УФ. Порекомендуйте каким образом это лучше сделать?
1 — 13.11.15 — 09:21
временное хранилище — в него пихай что хошь, лишь бы сериализовалось
2 — 13.11.15 — 09:25
а тогда как на сервере разберётся этот файл если там excell не стоит. временное хранилище подойдёт если предварительно его в Табличный документ сконвертировать, или таблицу значений
3 — 13.11.15 — 09:26
любой формат который не трубует открытия сторонней программы
4 — 13.11.15 — 09:28
есть какая то функция которая бы лист ексель в файл типа «табличный документ» перевела?
5 — 13.11.15 — 09:28
а задача какая? что в этом файле?
У меня обработка для 1С с компонентой на Питоне читает и грузит эксели без Экселя.
Читает все форматы, работает во всех режимах 1С. и на всех операционках, даже на линуксе.
Скорость 100 000 строк в минуту.
6 — 13.11.15 — 09:29
а картошку она чистить умеет?
7 — 13.11.15 — 09:29
(4) есть встроенный метод табличного поля Прочитать()
Но не уверен что он работает на всех форматах экселя.
8 — 13.11.15 — 09:29
УФ ?
9 — 13.11.15 — 09:30
в метода Прочитать() в параметрах путь к файлу.
10 — 13.11.15 — 09:30
(5) а питон требуется устанавливать?
11 — 13.11.15 — 09:31
(9) это касательно моего 4 сообщения?
12 — 13.11.15 — 09:33
(0) Табличная часть. Заполнять на клиенте. После чтения данных в табличную часть сходить на сервер и там все обработать.
13 — 13.11.15 — 09:39
МассивДанных = РабочийЛист.UsedRange.Value.Выгрузить();
14 — 13.11.15 — 09:42
(12) на клиенте — ту уй когда что заполнишь.
клиент 1С работает только с формой.
никакие заполнения чего либо и тп в нем не существует.
15 — 13.11.15 — 09:43
И таблицу значений передавать тоже нельзя
16 — 13.11.15 — 09:44
(13) Подскажи пож-та ещё как собрать обратно в табличный документ из массива
17 — 13.11.15 — 09:45
(14) ты ври , да не завирайся
18 — 13.11.15 — 09:46
(14) > никакие заполнения чего либо и тп в нем не существует.
нельзя к чему обращаться ?
19 — 13.11.15 — 09:46
(14) Ты сам то пробовал? Табличные части вполне себе заполняются на клиенте. Открой любой документ с табличной частью.
20 — 13.11.15 — 09:48
21 — 13.11.15 — 09:48
(19) Открыл. что дальше?))))
22 — 13.11.15 — 09:48
+ (19) И для особо любознательных Маней могу сообщить — обработка также может иметь табличную часть. И точно также ее можно заполнить на клиенте. А доступна она будет на сервере без всяких извратов. Просто в контексте открытой формы.
23 — 13.11.15 — 09:49
(21) не умеешь к с ТЧ работать на клиенте ?
24 — 13.11.15 — 09:50
(21) Дальше пробуй ее заполнять.
25 — 13.11.15 — 09:50
(22) ты идиот? ну и что что табличная часть у обработки.
в процедурах клиента НИКАКИЕ методы не доступны по работе с данными в ПРИНЦИПЕ.
там куда не плюнь идет вызов дальнейших процедур НА СЕРВЕРЕ.
И клиент-серверной базе это значит что все это фактически осуществляется на сервере!
26 — 13.11.15 — 09:51
(25) «ты идиот?» Держи себя в руках.
27 — 13.11.15 — 09:52
уговорил, черт языкастый
МассивДанных = РабочийЛист.UsedRange.Value.Выгрузить();
РабочийЛист = Неопределено;
Док.Close();
Книги = Неопределено;
Ексель = Неопределено;
ВсегоСтрок = МассивДанных.ВГраница();
НомерКолонки = 0;
ТаблицаДляЗагрузкиОчиститьНаСервере();
Для Каждого КолонкаЛиста Из МассивДанных Цикл
НомерКолонки = НомерКолонки + 1;
НомерСтроки = 0;
Для каждого ЗначениеЯчейки Из КолонкаЛиста Цикл
НомерСтроки = НомерСтроки + 1;
Если ЗначениеЯчейки = Неопределено Тогда
Продолжить;
КонецЕсли;
ТаблицаДляЗагрузки.Область(НомерСтроки,НомерКолонки).Текст = СокрЛП(ЗначениеЯчейки);
ТаблицаДляЗагрузки.Область(НомерСтроки,НомерКолонки).ГраницаСверху = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная,);
ТаблицаДляЗагрузки.Область(НомерСтроки,НомерКолонки).ГраницаСнизу = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная,);
ТаблицаДляЗагрузки.Область(НомерСтроки,НомерКолонки).ГраницаСлева = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная,);
ТаблицаДляЗагрузки.Область(НомерСтроки,НомерКолонки).ГраницаСправа = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная,);
ТаблицаДляЗагрузки.Область(НомерСтроки,НомерКолонки).ЦветРамки = Новый Цвет(179,172,134);
КонецЦикла;
КонецЦикла;
28 — 13.11.15 — 09:52
(26) нефиг нести ересь.
29 — 13.11.15 — 09:53
тише тише ребята!
проблема фигня))))) не стоит из-за неё ругаться!
30 — 13.11.15 — 09:53
(27) чувак. Экселя нет! Ты сабж читал?
31 — 13.11.15 — 09:54
(27) спасибо!
32 — 13.11.15 — 09:54
+ (26) Никогда не видел расчет суммы в табличной части? Например в событии ПриИзменении?
Типа такого :
текСтрока.Сумма = текСтрока.Количество * текСтрока.Цена;
При этом на сервер за такой фигней никто управление не гоняет.
Прочитай книжку «Разработка управляемого интерфейса» — потом начинай надувать пузыри соплями.
33 — 13.11.15 — 09:54
меня забанили на время как то, теперь культурный стал, и Вам рекомендую)))
34 — 13.11.15 — 09:57
для себя сделал вывод что, нуна в табличный документ, его передавать на сервер и там разбирать. любые методы на сервере типа
Эксель = Новый COMОбъект(«Excel.Application»);
не применимы , поскольку такого приложения нет.
35 — 13.11.15 — 09:58
(34) Не в табличный документ. А в табличную часть.
36 — 13.11.15 — 09:58
P.S.
Тип «Табличный документ» передавать можно
37 — 13.11.15 — 09:58
(36) А табличная часть доступна в контексте. Без всяких передач.
38 — 13.11.15 — 09:59
(34) даже если будет стоять на сервере. ты там с комом нормально работать не сможешь.
39 — 13.11.15 — 09:59
(25)
какие проблемы в открой форме на клиенте заполнить таблицу (ТаблицаЗначений/ТабличнаяЧасть) ?
40 — 13.11.15 — 09:59
(35) мне нужно лишь временное хранилище файла, для этого не обязательно ещё и конструировать табличную часть
41 — 13.11.15 — 10:01
Всё не читал, но осуждаю © миста
а почто-ж не такой способ?
scr = СоздатьОбъект(«MSScriptControl.ScriptControl»);
scr.language = «javascript»;
scr.eval(«MyArray=new Array()»);
.. и т.д..
читаем Exel»евские файлы.. обрабатываем инфу, радуем бд..
ась?
42 — 13.11.15 — 10:01
(38) не надо распространять свой опыт на всех
че-то у меня все работает — хоть на клиенте, хоть на сервере
что за проблемы с комом на сервере?
43 — 13.11.15 — 10:01
(39) еперный балет.
ВЫ САБЖ ЧИТАЛИ?
Да пусть будет таблица — хоть я не знаю вагон таблиц.
на КЛИЕНТЕ ты не запустишь КОМ чтоыб считать ЭКАСЕЛЬ!
А значит по факту НИКАКИМ боком никак ты эту ТЗ НЕ ЗАПОЛНИШЬ!
Просто тупо потому что эксель не считаешь.
44 — 13.11.15 — 10:03
(42) элементарная проблема — ЭКСЕЛЯ НЕТ.
какой нафиг ком тут может быть.
45 — 13.11.15 — 10:03
Я уже молчу про то что если на сервере вообще будет линукс стоять;
46 — 13.11.15 — 10:04
Всё не читал, но сообщу, что у меня успешно работает обработка чтения файла Excelом на клиенте, записывает данные в Объект.МояТаблица
А на платформе 8.3.6 и выше можно спокойно на сервере читать без Excel’я.
47 — 13.11.15 — 10:04
(44)
ну прям, не знаю
&НаКлиенте
Процедура КомандаЗагрузитьТаблицуИзФайла(Команда)
ИмяФайла = «»;
Если Не ВыбратьФайлДляЗагрузки(ИмяФайла) Тогда
Возврат;
КонецЕсли;
Попытка
Ексель = Новый COMОбъект(«Excel.Application»); //ПолучитьCOMОбъект()
Книги = Ексель.Workbooks;
Ексель.DisplayAlerts = Ложь;
Исключение
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ОписаниеОшибки(),Объект);
Ексель = Неопределено;
Возврат;
КонецПопытки;
Попытка
Док = Книги.Open(ИмяФайла);
Исключение
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ОписаниеОшибки(),Объект);
Ексель = Неопределено;
Возврат;
КонецПопытки;
Для каждого РабочийЛист Из Док.WorkSheets Цикл
Прервать;
КонецЦикла;
Если Объект.ВидДокумента = ПредопределенноеЗначение(«Перечисление.ВидыДокументовИзмененияСписковЗастрахованных.ОбновлениеСписков») Тогда
Объект.ИдентификаторСписка = Лев(Док.Name,Найти(Док.Name,».»)-1);
КонецЕсли;
МассивДанных = РабочийЛист.UsedRange.Value.Выгрузить();
РабочийЛист = Неопределено;
Док.Close();
Книги = Неопределено;
Ексель = Неопределено;
ВсегоСтрок = МассивДанных.ВГраница();
НомерКолонки = 0;
ТаблицаДляЗагрузкиОчиститьНаСервере();
Для Каждого КолонкаЛиста Из МассивДанных Цикл
НомерКолонки = НомерКолонки + 1;
НомерСтроки = 0;
Для каждого ЗначениеЯчейки Из КолонкаЛиста Цикл
НомерСтроки = НомерСтроки + 1;
Если ЗначениеЯчейки = Неопределено Тогда
Продолжить;
КонецЕсли;
ТаблицаДляЗагрузки.Область(НомерСтроки,НомерКолонки).Текст = СокрЛП(ЗначениеЯчейки);
ТаблицаДляЗагрузки.Область(НомерСтроки,НомерКолонки).ГраницаСверху = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная,);
ТаблицаДляЗагрузки.Область(НомерСтроки,НомерКолонки).ГраницаСнизу = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная,);
ТаблицаДляЗагрузки.Область(НомерСтроки,НомерКолонки).ГраницаСлева = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная,);
ТаблицаДляЗагрузки.Область(НомерСтроки,НомерКолонки).ГраницаСправа = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная,);
ТаблицаДляЗагрузки.Область(НомерСтроки,НомерКолонки).ЦветРамки = Новый Цвет(179,172,134);
КонецЦикла;
КонецЦикла;
КонецПроцедуры
я запущу на клиенте ексель
48 — 13.11.15 — 10:04
EXCEL я НЕТУ!!!! В этом особенность вопроса товарищи!
49 — 13.11.15 — 10:05
(48) На клиенте?
50 — 13.11.15 — 10:05
(0) КОроче говоря делаешь на форме Табличное поле.
Тупо копи пастом из экселя копируешь и вставляешь все в 1С.
Тут тебе ни эксель, ни вообще капли кода не нужно в принципе.
И делай что душе угодно.
51 — 13.11.15 — 10:06
(48) ты читал (41) ?
У нас на всех компах предприятия установлен ОО, ексель уничтожен.
Читаем MSSC
52 — 13.11.15 — 10:07
(49) даже если на КЛИЕНТЕ будет ЭКСЕЛЬ!
КОМ работает только с ирективой &НаСервере!!!!
ну жесть просто. как такие вещи не знать.
Модератор
53 — 13.11.15 — 10:08
Не нужно так кричать.
54 — 13.11.15 — 10:09
(48)
а я понял, что на клиенте есть:
.Проблема в том, что на СЕРВЕРЕ Excell не установлен и установка запрещена. Таким образом файлик excell разбираем на КЛИЕНТЕ и в каком то формате необходимо передать на сервер.
55 — 13.11.15 — 10:09
&НаКлиенте
+ Code
Процедура КомандаЗагрузитьТаблицуИзФайла(Команда)
ИмяФайла = «»;
Если Не ВыбратьФайлДляЗагрузки(ИмяФайла) Тогда
Возврат;
КонецЕсли;
Попытка
Ексель = Новый COMОбъект(«Excel.Application»); //ПолучитьCOMОбъект()
56 — 13.11.15 — 10:09
(55) это рабочий код, вот прям щас выполнил еще раз,
57 — 13.11.15 — 10:10
прям, страшно становится — я вот сейчас узнаю. что КОМ работает только с диррективой «на сервере» и оно у меня перестанет работать
58 — 13.11.15 — 10:10
Весь код приводить не буду, вот названия функций для чтения на улиенте 3-мя способами:
&НаКлиенте
Excel_ПолучитьДанные_COM_НаКлиенте
Excel_ПолучитьДанные_ADO_НаКлиенте
Excel_ПолучитьДанные_COMArray_НаКлиенте
Это работает на клиенте:
НоваяСтрока = Объект.ДанныеExcel.Добавить();
Поле = Лист.Cells(НомерСтроки, НомерКолонки);
ЗначениеЯчейки = Поле.Value;
59 — 13.11.15 — 10:11
Маня в очередной раз не смог втулить свои поделки?
60 — 13.11.15 — 10:12
Повторюсь для уточнения! на клиенте excell есть, на сервере excell нету!
61 — 13.11.15 — 10:12
Вот процедура которая используя КОМ работает на клиенте. Может я что-то не так делаю?
&НаКлиенте
Процедура ПортПринтераНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
Спис = Новый СписокЗначений;
Попытка
WshNetwork = Новый COMОбъект(«WScript.Network»);
Исключение
Стр = «Не удалось создать объект «»WScript.Network»»
|Невозможно организовать выбор принтера»;
ПоказатьПредупреждение(,Стр);
КонецПопытки;
Если WshNetwork = Неопределено Тогда
Возврат;
КонецЕсли;
Принтеры = WshNetwork.EnumPrinterConnections();
Для Сч=0 По Принтеры.length-1 Цикл
Спис.Добавить(Принтеры.Item(сч+1));
сч=сч+1;
КонецЦикла;
ПортПринтера = ВыбратьИзСписка(Спис, Элементы.ПортПринтера);
КонецПроцедуры
62 — 13.11.15 — 10:14
(60) ну так открывай excel на клиенте, бери из него данные и передавай на сервер. в чем проблема то?
63 — 13.11.15 — 10:14
КОМ работает и на сервере и на клиенте, в зависимости что он вызывает, если ком вызывает ексель, а он не установлен, соответственно вылезить ошибко!
64 — 13.11.15 — 10:15
(62) Так ведь я и спросил, каким образом его будет удобней и лучше передать из формата excell на сервер, в последствии создавая документ поступления
65 — 13.11.15 — 10:19
66 — 13.11.15 — 10:19
(64) ды госпади. как угодно передавай. разве это вопрос.
67 — 13.11.15 — 10:20
так что маня слился ?
68 — 13.11.15 — 10:20
+ (65) Оно заполняется на клиенте. И доступно на сервере без всяких танцев. Просто в контекстном вызове.
69 — 13.11.15 — 10:20
(64) Неужели азы расписывать?
НаКлиенте:
НоваяСтрока = Объект.ДанныеExcel.Добавить();
НоваяСтрока.Колонка1 = Лист.Cells(НомерСтроки, НомерКолонки).Value;
НаСервере
Для каждого СтрокаТЧ Из Объект.ДанныеExcel Цикл
ЗначениеИзЭкселя = СтрокаТЧ.Колонка1;
70 — 13.11.15 — 10:22
(69) Он до сих пор не понял что ТабличнаяЧасть <> ПолеТабличногоДокумента.
71 — 13.11.15 — 10:23
+ (70) А Маня его убедил, что код
НоваяСтрока = Объект.ДанныеExcel.Добавить();
возможно выполнить только на сервере. Ибо маня так не знает, а значит оно невозможно.
72 — 13.11.15 — 10:32
(69) это и на клиенте можно полностью. Если колонки все выведены на форму.
73 — 13.11.15 — 10:35
(72) можно, но на сервере нужно найти номенклатуру по данным из файла…
74 — 13.11.15 — 10:45
занят сейчас. у меня продажа на 50 тысяч.с клиентом общаюсь.
75 — 13.11.15 — 10:49
Я с вами уже просто запарился. Да на клиенте моджно с объектами работать и примитивными методами.
Но этого мало в последующих вещах.
Я разработку писал не 1 день, и граблей там достаточно.
К тому же у меня требования иные изначально в подходе: никаких комов, никаких эксельей, вплоть до автозагрузки на сервере без каких либо форм.
76 — 13.11.15 — 10:54
(75) Как то это не согласуется с
«в процедурах клиента НИКАКИЕ методы не доступны по работе с данными в ПРИНЦИПЕ.» ЦЫ(26).
77 — 13.11.15 — 10:56
(76) Я человек который никогда на мелочи не обращает внимания.
Поэтому у меня в голове гораздо глобальнее вещи лежат, которые на три шага вперед продумывают что будет дальше.
78 — 13.11.15 — 10:57
У маньяка ком не работает на клиенте?
79 — 13.11.15 — 10:58
(77) слив засчитан
80 — 13.11.15 — 10:58
Мля, маня, иногда вообще задумываешься, а как ты пишешь то свои супер разработки с твоими знаниями =)
81 — 13.11.15 — 10:59
(80) я с комом попрощался изначально 4 года назад.
На тот момент он на клиенте не работал.
82 — 13.11.15 — 10:59
(80) ты открой любую его поделку — увидишь
83 — 13.11.15 — 11:00
(52) на помедитируй =)
COMОбъект (COMObject)
Конструкторы:
По имени приложения
Описание:
Создает COM-объект (например, Word, Excel и т.д.). Методы и свойства СОМ-объектов в дальнейшем становятся доступными через данный объект.
Доступность:
ТОНКИЙ КЛИЕНТ, веб-клиент, сервер, толстый клиент, внешнее соединение.
84 — 13.11.15 — 11:00
Даже если и сейчас работает — мне ком этот нафиг не вперся.
У меня давно уже давно основаная задача это автозагрузка данных в регламентном задании на сервере.
85 — 13.11.15 — 11:00
(82) Я открывал, на пред работе покупали (до меня ^^), комментировать не буду, ибо антиреклама =)
86 — 13.11.15 — 11:01
(83) ну значит в последних платформах разрешили.
87 — 13.11.15 — 11:01
(84) Сейчас? А когда не работал?
88 — 13.11.15 — 11:03
(87) ты думаешь я точно помню?
У меня на УФ обработка вышла на второй день выхода УТ11.
89 — 13.11.15 — 11:03
(84) «мне ком этот нафиг не вперся»
А ты свою хню на питоне как запускаешь?
90 — 13.11.15 — 11:03
а не использовать загрузку через ком объекты еще не предлагали?
Что-нибудь типа вот так
ТабДок = Новый ТабличныйДокумент;
ТабДок.Прочитать(«С:/Эксель.xlsx»);
ПостроительЗапроса = Новый ПостроительЗапроса;
ПостроительЗапроса.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТабДок.Область());
ПостроительЗапроса.Выполнить();
ТаблицаИтоговая = ПостроительЗапроса.Результат.Выбрать();
91 — 13.11.15 — 11:04
естественно предварительно файлик передав на сервер.
92 — 13.11.15 — 11:05
(89) что значит хнюб на питоне.
Питон — высокоуровневый язык программирования.
У меня ДЛЛ. Нативная. Для нее не нужно ничего. Работает на всех операционках.
93 — 13.11.15 — 11:06
(90) книги она читать не умеет.
да и кажется работает только с какими то отсталыми форматами экселя.
94 — 13.11.15 — 11:07
(85) они ещё могут кстати из базы данные удалятьт
95 — 13.11.15 — 11:07
Я точно не помню экселем кажись полнейшая лажа с считыванием листов экселя.
96 — 13.11.15 — 11:07
(94) да ладно тебе, пусть маня сам со своими клиентами разбирается =)
97 — 13.11.15 — 11:07
(93) xls,xlsx,ods читает.
единственный косяк, если несколько листов, то читает все.
лист от листа отделяется пустой строкой в таблице
НО! работает ОЧЕНЬ быстро и нативно.
Не надо париться с установкой эксель.
Очень удобно, возможно это то, что нужно автору.
98 — 13.11.15 — 11:08
(90) а если листов несколько? оно будет работать?
99 — 13.11.15 — 11:08
(96) у него политика простая — я за свои обработки не отвечаю
100 — 13.11.15 — 11:09
(98) с листами есть нюансы. но, кстати, можно перед загрузкой с помощью ПостроительЗапроса, решить вопросы листов. никто не мешает. в любом случае проще и универсальнее чем с экселем париться.
На чтение 9 мин Просмотров 27к. Опубликовано 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 без программирования.
Для сохранения табличного документа (например, результата отчета) можно вызвать команду Сохранить или Сохранить как… главного меню.
В открывшемся окне требуется выбрать каталог, имя и формат сохраняемого файла.
Для сохранения данных динамических списков (например, списка номенклатуры) необходимо:
- Вывести данные в табличный документ при помощи команды Еще ⇒ Вывести список…;
- Сохранить табличный документ в требуемый формат.
MS Excel на данный момент является одной из самых распространенных и любимых программ для работы с электронными таблицами. Поэтому зачастую программистам приходится сталкиваться с просьбами пользователей загрузить Excel файл в 1С 8.3.
Ниже будут рассмотрены два способа загрузки: в документ (накладная или установка цены) и в табличный документ. Получившиеся обработку можно скачать по ссылке.
Содержание
- Загрузка из Excel в документ 1С
- 1 шаг – интерфейс
- 2 шаг – процедура выбора файла
- 3 шаг – обработка файла Excel
- 4 шаг – создание документа и заполнение его данными
- Загрузка данных из Excel в табличный документ
Загрузка из Excel в документ 1С
В качестве примера выберем такой документ, как «Установка цен номенклатуры» в программе 1С Бухгалтерия 3.0. Задачей будет создать документ, заполнить основные реквизиты шапки и заполнить табличную часть «Товары» из Excel файла.
1 шаг – интерфейс
В рамках данной задачи достаточно разместить на форме поле ввода с кнопками выбора, очистки и открытия для выбора файла Excel и кнопку «Загрузить» для выполнения обработки по созданию и заполнению документа «Установка цен номенклатуры».
2 шаг – процедура выбора файла
Наша команда предоставляет услуги по консультированию, настройке и внедрению 1С.
Связаться с нами можно по телефону +7 499 350 29 00.
Услуги и цены можно увидеть по ссылке.
Будем рады помочь Вам!
Для того чтобы открыть и выбрать Excel файл из 1С 8.3, необходимо в событии «НачалоВыбора» поля ввода вызвать ДиалогВыбораФайла с заранее установленным фильтром:
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие); Диалог.Заголовок = "Выберите excel - файл"; Диалог.ПолноеИмяФайла = "c:"; Диалог.Фильтр = "Таблицы (*.xls,*.xlsx)|*.xls;*.xlsx;|Microsoft Excel 97/2000/XP/2003 (*.xls)|*.xls|Microsoft Excel 2007/2010 (*.xlsx)|*.xlsx"; Если Диалог.Выбрать() Тогда Объект.ФайлExcel = Диалог.ПолноеИмяФайла; КонецЕсли;
Для работы на web-клиенте, в браузере необходимо подключить расширение работы с файлами.
3 шаг – обработка файла Excel
В рамках данного шага реализуется открытие файла Excel, выбор первого листа (по желанию можно выбрать любой другой), расчет количества строк и колонок с данными.
// Попытка открытия файла Excel Попытка Excel = Новый COMОбъект("Excel.Application"); Excel.WorkBooks.Open(Объект.ФайлExcel); Исключение Сообщить("При открытии файла произошла ошибка! Операция прервана!"); Сообщить(ОписаниеОшибки()); Возврат; КонецПопытки; // Попытка выбрать первый лист // Можно указать любой другой Попытка Excel.Sheets(1).Select(); Исключение // Закрытие файла в том случае, если первый лист не найден Excel.ActiveWorkbook.Close(); Excel = 0; Сообщить("Первый лист не найден!"); ОтменитьТранзакцию(); Возврат; КонецПопытки; // Вычисление количества строк и колонок в зависимости от версии Excel vExcel = Лев(Excel.Version, Найти(Excel.Version,".")-1); Если vExcel = "8" тогда КоличествоСтрок = Excel.Cells.CurrentRegion.Rows.Count; КоличествоКолонок = Макс(Excel.Cells.CurrentRegion.Columns.Count, 13); Иначе КоличествоСтрок = Excel.Cells(1,1).SpecialCells(11).Row; КоличествоКолонок = Excel.Cells(1,1).SpecialCells(11).Column; Конецесли;
4 шаг – создание документа и заполнение его данными
После того, как файл Excel успешно открыт и были получены все необходимые данные, можно приступать к созданию документа и его заполнению.
Ниже приведен алгоритм, которым можно воспользоваться в том случае, если файл содержит множество колонок, но загрузить нужно лишь те, которые есть в документе 1С. Так же его можно использовать, когда есть необходимость проверить имена колонок на соответствие именам реквизитов для исключения ошибок.
// Проверка корректности заполнения колонок // Имена колонок в Excel файле должны совпадать с именами реквизитов табличной части, в которую загружаются данные // Переменная МассивКолонок содержит список номеров колонок, которые будут перегружаться МассивКолонок = Новый ТаблицаЗначений; МассивКолонок.Колонки.Добавить("НомерКолонки"); МассивКолонок.Колонки.Добавить("НазваниеКолонки"); Для КолонкаОтсчета = 1 по КоличествоКолонок Цикл ИмяКолонки = Excel.Cells(1, КолонкаОтсчета).Text; // Удаление лишних пробелов из имен колонок ИмяБезПробелов = СтрЗаменить(ИмяКолонки," ",""); // Проверка наличия реквизитов табличной части "Товары" в документе "УстановкаЦен" Если НЕ НаличиеРеквизитаТЧ(ИмяБезПробелов, Метаданные.Документы.УстановкаЦенНоменклатуры, "Товары") Тогда Сообщить("Не найден реквизит с именем " + ИмяБезПробелов + "! Колонка не будет загружена!"); Иначе НовСтрока = МассивКолонок.Добавить(); НовСтрока.НомерКолонки = КолонкаОтсчета; НовСтрока.НазваниеКолонки = ИмяБезПробелов; КонецЕсли; КонецЦикла;
Вызываемая функция «НаличиеРеквизитаТЧ(ИмяРекв, МетаданныеДок, ИмяТЧ)» проверяет в метаданных документа наличие реквизита выбранной нами табличной части (в данном случае «Товары») по его имени. Функция является универсальной, но если на практике задача загрузки файлов из Excel встречается не часто можно вместо нее сразу указать имена реквизитов табличной части документа для сравнения.
// Проверка наличия реквизита табличной части документа // Возвращает тип Булево // Истина - реквизит найден // Ложь - реквизит не найден &НаСервере Функция НаличиеРеквизитаТЧ(ИмяРекв, МетаданныеДок, ИмяТЧ) // Проверка наличия ТЧ ТЧ = МетаданныеДок.ТабличныеЧасти.Найти(ИмяТЧ); Если ТЧ = Неопределено Тогда // Нет такой таб. части в документе Возврат Ложь; Иначе Возврат НЕ (ТЧ.Реквизиты.Найти(ИмяРекв) = Неопределено); КонецЕсли; КонецФункции
После того, как был сформирован список загружаемых колонок, нужно приступать к созданию и заполнению самого документа. В данном примере обязательным условием является наличие в файле Excel колонки с названием «Номенклатура» потому что данный реквизит является обязательным к заполнению.
// Если есть колонки для загрузки // и есть колонка "Номенклатура, которая является обязательным к заполнению реквизитом Если МассивКолонок.Количество() <> 0 и МассивКолонок.НайтиСтроки(Новый Структура("НазваниеКолонки", "Номенклатура")).Количество() <> 0 Тогда // Создание документа и заполнение реквизитов шапки НовыйДокумент = Документы.УстановкаЦенНоменклатуры.СоздатьДокумент(); НовыйДокумент.Дата = ТекущаяДата(); НовыйДокумент.ТипЦен = Справочники.ТипыЦенНоменклатуры.НайтиПоНаименованию("Оптовая цена", Истина); НовыйДокумент.Ответственный = ПараметрыСеанса.ТекущийПользователь; НовыйДокумент.Комментарий = "Загружено из файла " + Объект.ФайлExcel; // Заполнение табличной части "Товары" // Переменная СтрокаОтсчета - номер строки в Excel, с которой начинается заполнение Для СтрокаОтсчета = 2 по КоличествоСтрок Цикл НСтр = НовыйДокумент.Товары.Добавить(); НСтр.Валюта = НовыйДокумент.ТипЦен.ВалютаЦены; Для каждого СтрокаМассив из МассивКолонок Цикл ТекущееЗначение = Excel.Cells(СтрокаОтсчета, СтрокаМассив.НомерКолонки).Text; // Получение имени колонки ИмяКолонки = Excel.Cells(1, СтрокаМассив.НомерКолонки).Text; // Заполнение строки данными Если ИмяКолонки = "Номенклатура" Тогда НСтр.Номенклатура = Справочники.Номенклатура.НайтиПоНаименованию(ТекущееЗначение, Истина); ИначеЕсли ИмяКолонки = "Цена" Тогда НСтр.Цена = ТекущееЗначение; КонецЕсли; КонецЦикла; КонецЦикла; // Запись и проведение документа НовыйДокумент.Записать(РежимЗаписиДокумента.Проведение); Сообщить("Создан и заполнен документ " + Строка(НовыйДокумент)); Иначе Сообщить("В Excel файле не достаточно данных для заполнения документа!"); КонецЕсли;
В результате данной обработки был создан, заполнен данными и проведен документ «Установка цен номенклатуры».
После завершения всех манипуляций с Excel файлом, его необходимо закрыть:
Excel.DisplayAlerts = 0; Excel.Quit(); Excel.DisplayAlerts = 1;
Загрузка данных из Excel в табличный документ
Начиная с версии платформы 8.3.6, фирма 1С добавила очень полезный метод, который позволяет загружать данные из Excel в табличный документ 1С. Данный метод применим для таких форматов, как *.xlsx, *.xls, *, ods.
В версии технологической платформы 1C 8.3.10 данный метод позволяет считывать отдельные листы файла, а не весь документ целиком.
Данный функционал реализован в виде метода «Прочитать» у объекта с типом «ТабличныйДокумент».
В качестве примера добавим на форму обработки табличный документ, куда будет выводиться Excel файл и кнопку со следующим кодом, выполняющимся на сервере:
ТабличныйДокумент.Прочитать(Объект.ФайлExcel);
В качестве параметра методу передается адрес нахождения файла текстовой строкой. Для больших файлов Excel данный метод может отрабатывать значительное время.
Результатом выполнения этого кода будет являться табличный документ с данными из Excel и сохранением оформления, что является весьма приятным бонусом. В рассмотренном примере исходный файл Excel содержал два листа, на каждом из которых была таблица. Результат метода «Прочитать» изображен ниже:
Смотрите также видео о загрузке с помощью типовой обработки:
Весьма частая задача, с которой сталкивается 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С.
- Download sample source code
Introduction
The adoption of XML as the native file format for Excel 2007 has opened up a whole host of new possibilities. Now for the first time we can create native Excel files on the server using standard tools. No longer is there a need to pollute your beautiful server room with a headless PC running Excel and an old VB6 app that uses OLE Automation to create reports. Such things can be consigned to the trash heap of IT history.
However, the new Office Open XML standard is so new there are precious few good code samples. This article aims to correct the situation by providing a flexible set of open source class libraries that you can use to create Excel spreadsheets on the server.
Why create Excel spreadsheets on the server?
Excel has long been recognized as the de facto standard when it comes to presenting management reports. The unique combination of great calculation engine, excellent charting facilities and the possibility to perform «what if» analysis, make it the «must have» business intelligence tool.
So when we came to replace our aging management reporting infrastructure, we set one key requirement: the new system must be Web-based and provide a «download in Excel» option. For our business intelligence project we built the data warehouse using SQL Server 2005 populated from our PeopleSoft and Novient implementations using SQL Server 2005 Integration Services (SSIS). The OLAP cube was built on SQL Server 2005 Analysis Services (SSAS). SQL Server 2005 Reporting Services (SSRS) provides the Web-based access to management reports and the all important «download in Excel» option. So why do we need to create Excel on the server?
The problem with SQL Server 2005 Reporting Services is that it the Excel spreadsheets it generates are «dumb». They contain no formula — just the raw data. So the recipient cannot perform a «what if» analysis by changing a few values and expecting the spreadsheet to recalculate.
We considered a number of ways to overcome this issue, but by far the most attractive is to create the Excel spreadsheet on the server, straight from the OLAP cube data. So we created a web-part for SharePoint Server 2007 so the user could enter their criteria and view the report on-line via Excel Services. Of course users can download the file for off-line viewing in Excel 2007 or even Excel 2003 file format. This SharePoint web-part and its associated web service that does the file format conversion will be the topic of another article.
The Open Source ExcelPackage Assembly
The ExcelPackage assembly is a set of classes and wrappers around the .NET 3.0 System.IO.Packaging
API and the new SpreadsheetML file format. It extracts away the complexity of dealing with the individual XML components that make up the new Excel 2007 file format. The classes are published as an assembly called ExcelPackage which you can install in the GAC and use as the basis of your own applications. In the sprit of open source projects, if you wish to help extend the functionality offered by the ExcelPackage assembly then join the team over at the ExcelPackage Open XML project.
Creating an Excel spreadsheet from scratch
Sample 1 shows how to create a new Excel spreadsheet containing some basic data and calculations. So let’s see how this is achieved.
using OfficeOpenXml; … FileInfo newFile = new FileInfo(@"C:mynewfile.xlsx"); using (ExcelPackage xlPackage = new ExcelPackage(newFile)) { … }
This creates a new instance of the all important ExcelPackage
class which gives you access to the Excel workbook and worksheets. If mynewfile.xlsx
already exists, then ExcelPackage will open the existing file. Otherwise mynewfile.xlsx
will be created from scratch.
Let’s start by adding a new worksheet called “Tinned Goods” and adding some basic data and a simple calculation:
ExcelWorksheet worksheet = xlPackage.Workbook.Worksheets.Add("Tinned Goods"); worksheet.Cell(1, 1).Value = "Product"; … worksheet.Cell(4, 1).Value = "Peas"; worksheet.Cell(5, 1).Value = "Total"; worksheet.Cell(1, 2).Value = "Tins Sold"; ExcelCell cell = worksheet.Cell(2, 2); cell.Value = "15"; string calcStartAddress = cell.CellAddress; worksheet.Cell(3, 2).Value = "32"; … worksheet.Cell(5, 2).Formula = string.Format("SUM({0}:{1})", calcStartAddress, calcEndAddress);
If all this seems a bit too easy — well yes it is! The ExcelPackage
assembly does all the hard work of creating the XML elements that are needed to represent an Excel worksheet, the Excel rows, the Excel cells etc. All you need to do is connect in the data! The ExcelWorksheet
class has all the properties and methods needed to create and manipulate worksheets. A number of supporting classes (such as ExcelCell
, ExcelRow
, ExcelColumn
, ExcelHeaderFooter
etc.) provide properties and methods of each worksheet component. They also provide helper functions that make it easy to manipulate Excel data. For example, the ExcelCell.GetCellAddress(iRow, iColumn)
method turns your row and column integers into Excel-style cell addresses.
Ok, so in our sample some of the data is too wide for the column, so let’s change the column size:
worksheet.Column(1).Width = 15;
Next, add some headers and footers to the spreadsheet. Note how we use the PageNumber and NumberOfPages constants to insert codes into the footer text. This causes Excel to insert the page number and the number of pages in the document footer. worksheet.HeaderFooter.oddHeader.CenteredText = «Tinned Goods Sales»;
worksheet.HeaderFooter.oddFooter.RightAlignedText = string.Format("Page {0} of {1}", ExcelHeaderFooter.PageNumber, ExcelHeaderFooter.NumberOfPages);
OK, so let’s write some real hard code. Let’s insert a line into the worksheet so we can add some more data. This will screw up our formula as it will be referencing the wrong set of rows (i.e. the new row will not be included in the total).
worksheet.InsertRow(3);
Well hell no, the formula is correct. The InsertRow
method not only updates all the row and cell references in the underlying XML, but also updates all the formulas in the spreadsheet! Ok, we now have our report, but we want to ensure our corporate search engine can find the file later. So let’s add some standard and custom document properties.
xlPackage.Workbook.Properties.Title = "Sample 1"; xlPackage.Workbook.Properties.Author = "John Tunnicliffe"; xlPackage.Workbook.Properties.SetCustomPropertyValue("EmployeeID", "1147");
Now save the file and all its components.
xlPackage.Save();
Below is a screenshot of the final output showing the header and the document properties.
Reading data from an Excel spreadsheet
Sample 2 shows how to read data from an existing Excel spreadsheet. We will use the spreadsheet generated by Sample 1 as the source document. To output the contents of column 2 to the console, this is all we need:
using (ExcelPackage xlPackage = new ExcelPackage(existingFile)) { ExcelWorksheet worksheet = xlPackage.Workbook.Worksheets[1]; int iCol = 2; for (int iRow = 1; iRow < 6; iRow++) Console.WriteLine("Cell({0},{1}).Value={2}", iRow, iCol, worksheet.Cell(iRow, iCol).Value); Console.WriteLine("Cell({0},{1}).Formula={2}", 6, iCol, worksheet.Cell(6, iCol).Formula); }
Here is the output from the sample code:
Starting with a template
Sample 3 shows how to create a new Excel spreadsheet based on an existing file and populate it with data from a database. This is a much better approach as you can quickly create a spreadsheet with the right formula and the correct corporate ‘look and feel’ using Excel 2007. You can then have the calculations in your template validated by the business before starting to write any code. This whole approach saves a lot of coding time!
Before running the code sample, open the template and take a look at its content. You will see it already has the desired layout and all the formula and formatting required for the title and total lines. However, it only has room for three «data rows» (i.e. rows 5, 6 & 7). You will see how we cope with this later.
So let’s start by creating a new Excel spreadsheet based on a template.
using OfficeOpenXml; assembly … FileInfo newFile = new FileInfo(@"C:sample3.xlsx"); FileInfo template = new FileInfo(@"C:sample3template.xlsx"); using (ExcelPackage xlPackage = new ExcelPackage(newFile, template)) {…}
Behind the scenes, the ExcelPackage
constructor simply copies the template and opens the new package. Now obtain a reference to the existing worksheet and initialize some variables:
ExcelWorksheet worksheet = xlPackage.Workbook.Worksheets["Sales"]; ExcelCell cell; const int startRow = 5; int row = startRow;
Next open a connection to the database and run the query. This example uses data from the AdventureWorks sample database, so you will need this installed if you want to run the sample.
while (sqlReader.Read()) { int col = 1; if (row > startRow) worksheet.InsertRow(row); for (int i = 0; i < sqlReader.FieldCount; i++) { if (sqlReader.GetName(i) == "EmailAddress") { string hyperlink = "mailto:" + sqlReader.GetValue(i).ToString(); worksheet.Cell(row, 1).Hyperlink = new Uri(hyperlink, UriKind.Absolute); } else { if (sqlReader.GetValue(i) != null) worksheet.Cell(row, col).Value = sqlReader.GetValue(i).ToString(); col++; } } row++; }
So now we have filled our worksheet with the entire dataset. Note how we use the email address as a hyperlink. Using hyperlinks is useful when you want to link one report up with another.
The purist among you will notice that all the data is written into the cell as a string. However, the Cell(row, col).Value = "xxx"
property assignment code checks if the value is a number or a string and sets the cell’s data type accordingly.
As mentioned earlier, the template only has room for three data rows. We cope with this by simply inserting rows into the template — thereby pushing the «Total» row down the sheet. The InsertRow
method automatically updates the formula in the «Total» row so that they take into account the extra rows.
As we have inserted a whole set of rows into the spreadsheet, they will not have the correct style. We correct this by simply iterating through the new rows and copying the style from the first row to all the other rows.
for (int iCol = 1; iCol <= 7; iCol++) { cell = worksheet.Cell(startRow, iCol); for (int iRow = startRow; iRow <= row; iRow++) { worksheet.Cell(iRow, iCol).StyleID = cell.StyleID; } }
The Power of Named Styles
Anyone familiar with styling HTML with CSS will understand the power and flexibility of using named styles rather than updating the style of every individual element. With named styles, the look and feel of the whole spreadsheet can be altered by changing one style definition. This capability was introduced in Excel 2003, but Excel 2007 goes one step further and makes it a dream to create a template using named styles.
We apply two built-in named styles to highlight the top achieving and the worst performing sales reps.
worksheet.Cell(startRow, 6).Style = "Good"; worksheet.Cell(row, 6).Style = "Bad";
The biggest problem with named styles in Excel 2007 is that if they are not used in your template, then Excel strips out the definition when the file is saved. This is a real headache. There are two ways to cope with this (1) add extra rows that have styles applied and delete them later (which is the technique used in this sample) or (2) load your own style.xml file which contains all the definitions you want to use.
Shared formula
Excel 2007 has a neat feature which saves a lot of coding when it comes to applying the same formula to a range of cells. A formula in one cell can be marked as «shared» and all cells referenced by the shared formula obtain their own version of the formula. So if cell E5
has the formula D5*12
, then cell E6
would have the formula D6*12
etc. etc. To set up a shared formula simply call the CreateSharedFormula
method. In the following example, the formula in cell E5
is marked as «shared» and all the other cells in the range E5:E21
are assigned their own variation of the formula.
worksheet.CreateSharedFormula(worksheet.Cell(5, 5), worksheet.Cell(21, 5));
Ensuring your formula are recalculated on File-Open
One problem we came across with Excel 2007 is that it does not automatically re-calculate the spreadsheet when it is re-opened — even when the Calculate option set to automatic! This is because the existing cells in the template have both a formula and a value in the cell. So Excel just assumes the value is correct and does not attempt to re-compute the formula. Of course, we have just added twenty rows of data and updated the formula references in the XML — but Excel has no why of knowing this, so assumes the values must be right!
The only way to force the recalculation is to ensure the cell has no value — just a formula. So the RemoveValue()
method becomes very useful for all formula in the worksheet. Hence:
worksheet.Cell(22, 5).RemoveValue();
Because of this phenomenon, we changed the ExcelCell.Formula property assignment code so that it removes the cell’s value when you assign the cell a formula.
The final output of Sample 3 code should look something like this — much more professional than anything that can be achieved starting from scratch.
Integrity issues
As soon as you start deleting rows or even worksheets from the package, you have potential for integrity issues. Your formulas will reference cells (or worksheets) that no longer exist. The ExcelPackage assembly does a good job of tidying up after you — but cannot cope with complex situations. You will soon know if you have an integrity problem — Excel will complain bitterly when opening the newly created file.
A classic problem is the calcChain.xml
file. This tells Excel in what order the calculations should be processed. So if you delete a row that is referenced by the calcChain, Excel will complain. However, if you simply remove the calcChain.xml
from the package, Excel re-creates it when the file is opened — and does not complain! So this is an easy fix. The ExcelPackage assembly does exactly that — deletes the calcChain.xml
file from the template so that Excel simply re-creates it when the file is opened.
The ExcelPackage assembly also provides you with direct access to each of the XML documents that make up the package. So you can write your own code to manipulate the XML directly. However, if you choose to do this, be careful to ensure the XML conforms to the new Office Open XML standard. Otherwise, Excel will simply strip out your all hard work as «badly formed».
Debugging your application
If you want to understand exactly what is been written into each of the component XML files by the ExcelPackage assembly, then simply add the following line of code:
xlPackage.DebugMode = true;
This will cause the assembly to output the raw XML files in the same location as the output file. You will see a sub-folder called ‘xl’ and another callled ‘docProps’.
Summary
This article has demonstrated just how easy it is to create Excel-based reports on the server using the open source ExcelPackage assembly. We hope you will be able to join us in extending the functionality of the assembly over at the ExcelPackage Open XML project. There is plenty still to do; charting, conditional formatting, inserting comments, to name just a few!
Good luck with your project!
John is a senior business intelligence developer / designer based in London, UK who likes to get his hands dirty doing real code.