Загрузка и обработка большого файла EXCEL в 1С с прогрессбаром

Задача: «фоново» загрузить файл эксель большого размера, с показом прогресса загрузки.

Решение:

В ходе выполнения задачи столкнулся с глюком платформы 1С, что при запуске фонового задания с параметром адреса временного хранилища файла, он приходит на сервер пустым. Потому пришлось делать «финт ушами», а именно перед запуском фонового задания, файл загрузить на сервер, получить его временное имя и уже затем передать его как параметр при запуске фонового задания.

Кроме того выплыла проблема с не рабочим способом передачи данных о загрузке при помощи хранения данных во «ВременныхХранилиах», описанным тут. Потому для получения прогресса воспользуемся возможностью зная идентификатор фонового процесса периодически получить с сервера данные выводимые при помощи «Сообщить()».

В общих модулях разместим следующий код фонового процесса:

&НаСервере
Функция ЗагрузкаФайлаПредварительная(АдресВременногоХранилищаФайла) Экспорт			
	ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресВременногоХранилищаФайла);
	ИмяВременногоФайлаСпр = ПолучитьИмяВременногоФайла("xlsx");
	ДвоичныеДанные.Записать(ИмяВременногоФайлаСпр);     
	возврат ИмяВременногоФайлаСпр;	
конецфункции	

Процедура ЗагрузкаФайлаДлительная(ИмяВременногоФайлаСпр) Экспорт			
		
    ТабличныйДокументСпр = Новый ТабличныйДокумент;
    ТабличныйДокументСпр.Прочитать(ИмяВременногоФайлаСпр,СпособЧтенияЗначенийТабличногоДокумента.Значение);
	
	//читаем все листы файла СправочникСМС
	Для Каждого ОбластьТД ИЗ ТабличныйДокументСпр.Области Цикл         		     
            ОбластьФайла = ТабличныйДокументСпр.ПолучитьОбласть(ОбластьТД.Имя);
            КолВоСтрокФайла = ОбластьФайла.ПолучитьРазмерОбластиДанныхПоВертикали();
            КолВоКолонокФайла = ОбластьФайла.ПолучитьРазмерОбластиДанныхПоГоризонтали();
            Сообщить("Строк:"+КолВоСтрокФайла);
            Сообщить("Колонок:"+КолВоКолонокФайла);         
            имялиста=ОбластьТД.Имя;
            Сообщить("Лист:"+имялиста);         
                    МассивИменКолонок=Новый Массив();
                    // читаем шапку листа
                    Для ит=1 ПО КолВоКолонокФайла Цикл
                        нКолонка = СтрЗаменить(ит, Символы.НПП, "");
                        ИмяКолонки=ОбластьФайла.ПолучитьОбласть("R3" + "C"+нКолонка).ТекущаяОбласть.Текст;                        
                        МассивИменКолонок.Добавить(ИмяКолонки);
					конеццикла; 					
					НачСтрока=3;КонСтрока=0;
                    НачСтрока = ?(НачСтрока = 0, 2, НачСтрока);
                    КонСтрока = ?(КонСтрока = 0, КолвоСтрокФайла, КонСтрока);
                    //перебираем все строки без первой строки  
					Индикатор=0;
                    Для нСтрокаТФ = НачСтрока+1 ПО КонСтрока Цикл
                        нСтрока = СтрЗаменить(нСтрокаТФ, Символы.НПП, "");                        
			если Окр(нСтрокаТФ*100/КонСтрока)<>Индикатор тогда
				Индикатор = Окр(нСтрокаТФ*100/КонСтрока);
				Сообщение = Новый СообщениеПользователю;
				Сообщение.Текст = "Выполнено %"+Индикатор;
				Сообщение.Сообщить();
			конецесли;
			Для нКолонкаТФ = 1 ПО КолВоКолонокФайла Цикл
                            нКолонка = СтрЗаменить(нКолонкаТФ, Символы.НПП, "");
                            Область = ОбластьФайла.ПолучитьОбласть("R"+нСтрока+"C"+нКолонка);
                            ТекущаяОбласть = Область.ТекущаяОбласть;
                            ЗначениеЯчейки = СокрЛП(ТекущаяОбласть.Текст);
			    ...
				обрабатываем файл
			    ...	
                        конеццикла;                         		
	конеццикла;
	Сообщение = Новый СообщениеПользователю;
	Сообщение.Текст = "Загрузка завершена.";
	Сообщение.Сообщить();

Клиентская часть в управляемых формах:

&НаКлиенте
Процедура Жмяк(Команда)
Режим = РежимДиалогаВыбораФайла.Открытие;
    ДиалогОткрытияФайла = Новый ДиалогВыбораФайла(Режим);
    ДиалогОткрытияФайла.ПолноеИмяФайла = "";
    Фильтр = НСтр("ru = 'Текст'; en = 'Text'")+ "(*.xls)|*.xlsx";
    ДиалогОткрытияФайла.Фильтр = Фильтр;
    ДиалогОткрытияФайла.МножественныйВыбор = ложь;
    ДиалогОткрытияФайла.Заголовок = "Выберите файлы";
    Если ДиалогОткрытияФайла.Выбрать() Тогда
        МассивФайлов = ДиалогОткрытияФайла.ВыбранныеФайлы;
		ФайлСМС="";
		Для Каждого ИмяФайла Из МассивФайлов Цикл
			ФайлСМС=ИмяФайла;
		конеццикла;
		если ФайлСМС<>"" тогда 			
					АдресХранилищаФайла = "";			
					Состояние("Перемещаю файл на сервер");
		            ПоместитьФайл(АдресХранилищаФайла, ФайлСМС, , Ложь, ЭтаФорма.УникальныйИдентификатор);   					
					Состояние("Обрабатывается файл "+ФайлСМС);							
					ЗапускФоновойЗагрузкиСправочника(АдресХранилищаФайла);					
					Состояние("Запущена фоновая обработка файла");
					ПодключитьОбработчикОжидания("ИндикаторВыполненияЗагрузки",1,ложь);	
		иначе
			сообщить("Файл не выбран");
		конецесли;	
	конецесли;	        

КонецПроцедуры


&НаСервере
Процедура ЗапускФоновойЗагрузкиСправочника(АдресХранилищаФайла)	
	ИмяВременногоФайлаСпр=СК_Регламентные.ЗагрузкаФайлаПредварительная(АдресХранилищаФайла);	
	МассивПараметров = Новый Массив;
	МассивПараметров.Добавить(ИмяВременногоФайлаСпр);		
	Сообщить("Адрес файла (1):"+АдресХранилищаФайла);									
	ФЗ = ФоновыеЗадания.Выполнить("СК_Регламентные.ЗагрузкаФайлаДлительная",МассивПараметров);	
	ЭтаФорма.ФоновоеИдентификатор = ФЗ.УникальныйИдентификатор;
	
							
КонецПроцедуры
&НаСервере
Функция ПолучитьСообщенияФЗ(ФЗ, Состояние = Неопределено, УдалятьСообщения = Ложь) Экспорт
	Если Состояние = Неопределено Тогда
		Состояние = ФЗ.Состояние;
	КонецЕсли;
	МассивСообщений = Новый Массив;
	Сообщения = ФЗ.ПолучитьСообщенияПользователю(УдалятьСообщения);
	Если Сообщения <> Неопределено Тогда
		Для Каждого Сообщение Из Сообщения Цикл
			МассивСообщений.Добавить(Сообщение.Текст);
		КонецЦикла;
	КонецЕсли;
	Возврат МассивСообщений;
КонецФункции

&НаСервере
Функция ОпроситьФоновые()
	прог=неопределено;
	ФЗ = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(ЭтаФорма.ФоновоеИдентификатор);
	ФСообщения=ПолучитьСообщенияФЗ(ФЗ,,истина);
	Если ФСообщения.Количество() > 0 Тогда
		Для Каждого Сообщение Из ФСообщения Цикл
			Сообщить(Сообщение);
			если найти(Сообщение,"%")>0 тогда
				Этаформа.Прогресс=СтрЗаменить(Сообщение,"Выполнено %","");			
				прог=Этаформа.Прогресс;
			конецесли;
		КонецЦикла;
	КонецЕсли;
	возврат прог;
КонецФункции
&НаКлиенте
Процедура ИндикаторВыполненияЗагрузки() Экспорт
	пр=ОпроситьФоновые();
	если пр<>неопределено тогда
		Состояние("Выполнено "+пр);
	конецесли;
КонецПроцедуры

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.