Загрузка и обработка большого файла EXCEL в 1С с прогрессбаром
Задача: «фоново» загрузить файл эксель большого размера, с показом прогресса загрузки.
Решение:
В ходе выполнения задачи столкнулся с глюком платформы 1С, что при запуске фонового задания с параметром адреса временного хранилища файла, он приходит на сервер пустым. Потому пришлось делать «финт ушами», а именно перед запуском фонового задания, файл загрузить на сервер, получить его временное имя и уже затем передать его как параметр при запуске фонового задания.
Кроме того выплыла проблема с не рабочим способом передачи данных о загрузке при помощи хранения данных во «ВременныхХранилиах», описанным тут. Потому для получения прогресса воспользуемся возможностью зная идентификатор фонового процесса периодически получить с сервера данные выводимые при помощи «Сообщить()».
В общих модулях разместим следующий код фонового процесса:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
&НаСервере Функция ЗагрузкаФайлаПредварительная(АдресВременногоХранилищаФайла) Экспорт ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресВременногоХранилищаФайла); ИмяВременногоФайлаСпр = ПолучитьИмяВременногоФайла("xlsx"); ДвоичныеДанные.Записать(ИмяВременногоФайлаСпр); возврат ИмяВременногоФайлаСпр; конецфункции Процедура ЗагрузкаФайлаДлительная(ИмяВременногоФайлаСпр) Экспорт ТабличныйДокументСпр = Новый ТабличныйДокумент; ТабличныйДокументСпр.Прочитать(ИмяВременногоФайлаСпр,СпособЧтенияЗначенийТабличногоДокумента.Значение); //читаем все листы файла СправочникСМС Для Каждого ОбластьТД ИЗ ТабличныйДокументСпр.Области Цикл ОбластьФайла = ТабличныйДокументСпр.ПолучитьОбласть(ОбластьТД.Имя); КолВоСтрокФайла = ОбластьФайла.ПолучитьРазмерОбластиДанныхПоВертикали(); КолВоКолонокФайла = ОбластьФайла.ПолучитьРазмерОбластиДанныхПоГоризонтали(); Сообщить("Строк:"+КолВоСтрокФайла); Сообщить("Колонок:"+КолВоКолонокФайла); имялиста=ОбластьТД.Имя; Сообщить("Лист:"+имялиста); МассивИменКолонок=Новый Массив(); // читаем шапку листа Для ит=1 ПО КолВоКолонокФайла Цикл нКолонка = СтрЗаменить(ит, Символы.НПП, ""); ИмяКолонки=ОбластьФайла.ПолучитьОбласть("R3" + "C"+нКолонка).ТекущаяОбласть.Текст; МассивИменКолонок.Добавить(ИмяКолонки); конеццикла; НачСтрока=3;КонСтрока=0; НачСтрока = ?(НачСтрока = 0, 2, НачСтрока); КонСтрока = ?(КонСтрока = 0, КолвоСтрокФайла, КонСтрока); //перебираем все строки без первой строки Индикатор=0; Для нСтрокаТФ = НачСтрока+1 ПО КонСтрока Цикл нСтрока = СтрЗаменить(нСтрокаТФ, Символы.НПП, ""); если Окр(нСтрокаТФ*100/КонСтрока)<>Индикатор тогда Индикатор = Окр(нСтрокаТФ*100/КонСтрока); Сообщение = Новый СообщениеПользователю; Сообщение.Текст = "Выполнено %"+Индикатор; Сообщение.Сообщить(); конецесли; Для нКолонкаТФ = 1 ПО КолВоКолонокФайла Цикл нКолонка = СтрЗаменить(нКолонкаТФ, Символы.НПП, ""); Область = ОбластьФайла.ПолучитьОбласть("R"+нСтрока+"C"+нКолонка); ТекущаяОбласть = Область.ТекущаяОбласть; ЗначениеЯчейки = СокрЛП(ТекущаяОбласть.Текст); ... обрабатываем файл ... конеццикла; конеццикла; Сообщение = Новый СообщениеПользователю; Сообщение.Текст = "Загрузка завершена."; Сообщение.Сообщить(); |
Клиентская часть в управляемых формах:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
&НаКлиенте Процедура Жмяк(Команда) Режим = РежимДиалогаВыбораФайла.Открытие; ДиалогОткрытияФайла = Новый ДиалогВыбораФайла(Режим); ДиалогОткрытияФайла.ПолноеИмяФайла = ""; Фильтр = НСтр("ru = 'Текст'; en = 'Text'")+ "(*.xls)|*.xlsx"; ДиалогОткрытияФайла.Фильтр = Фильтр; ДиалогОткрытияФайла.МножественныйВыбор = ложь; ДиалогОткрытияФайла.Заголовок = "Выберите файлы"; Если ДиалогОткрытияФайла.Выбрать() Тогда МассивФайлов = ДиалогОткрытияФайла.ВыбранныеФайлы; ФайлСМС=""; Для Каждого ИмяФайла Из МассивФайлов Цикл ФайлСМС=ИмяФайла; конеццикла; если ФайлСМС<>"" тогда АдресХранилищаФайла = ""; Состояние("Перемещаю файл на сервер"); ПоместитьФайл(АдресХранилищаФайла, ФайлСМС, , Ложь, ЭтаФорма.УникальныйИдентификатор); Состояние("Обрабатывается файл "+ФайлСМС); ЗапускФоновойЗагрузкиСправочника(АдресХранилищаФайла); Состояние("Запущена фоновая обработка файла"); ПодключитьОбработчикОжидания("ИндикаторВыполненияЗагрузки",1,ложь); иначе сообщить("Файл не выбран"); конецесли; конецесли; КонецПроцедуры &НаСервере Процедура ЗапускФоновойЗагрузкиСправочника(АдресХранилищаФайла) ИмяВременногоФайлаСпр=СК_Регламентные.ЗагрузкаФайлаПредварительная(АдресХранилищаФайла); МассивПараметров = Новый Массив; МассивПараметров.Добавить(ИмяВременногоФайлаСпр); Сообщить("Адрес файла (1):"+АдресХранилищаФайла); ФЗ = ФоновыеЗадания.Выполнить("СК_Регламентные.ЗагрузкаФайлаДлительная",МассивПараметров); ЭтаФорма.ФоновоеИдентификатор = ФЗ.УникальныйИдентификатор; КонецПроцедуры &НаСервере Функция ПолучитьСообщенияФЗ(ФЗ, Состояние = Неопределено, УдалятьСообщения = Ложь) Экспорт Если Состояние = Неопределено Тогда Состояние = ФЗ.Состояние; КонецЕсли; МассивСообщений = Новый Массив; Сообщения = ФЗ.ПолучитьСообщенияПользователю(УдалятьСообщения); Если Сообщения <> Неопределено Тогда Для Каждого Сообщение Из Сообщения Цикл МассивСообщений.Добавить(Сообщение.Текст); КонецЦикла; КонецЕсли; Возврат МассивСообщений; КонецФункции &НаСервере Функция ОпроситьФоновые() прог=неопределено; ФЗ = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(ЭтаФорма.ФоновоеИдентификатор); ФСообщения=ПолучитьСообщенияФЗ(ФЗ,,истина); Если ФСообщения.Количество() > 0 Тогда Для Каждого Сообщение Из ФСообщения Цикл Сообщить(Сообщение); если найти(Сообщение,"%")>0 тогда Этаформа.Прогресс=СтрЗаменить(Сообщение,"Выполнено %",""); прог=Этаформа.Прогресс; конецесли; КонецЦикла; КонецЕсли; возврат прог; КонецФункции &НаКлиенте Процедура ИндикаторВыполненияЗагрузки() Экспорт пр=ОпроситьФоновые(); если пр<>неопределено тогда Состояние("Выполнено "+пр); конецесли; КонецПроцедуры |