Выбор файла и загрузка его на сервер в асинхронном режиме

22.10.17

Разработка - Универсальные функции

Несколько библиотечных процедур, упрощающих жизнь разработчика при отключенном режиме модальности.

Скачать исходный код

Наименование Файл Версия Размер
Выбор файла и загрузка его на сервер в асинхронном режиме 8.3 (УФ+ОФ)
.epf 13,67Kb
113
.epf 13,67Kb 113 Скачать

Введение

С появлением управляемого приложения и веб-клиента некоторые задачи, которые решались в обычном приложением за несколько строчек, существенно усложнились. Казалось бы такая простая и часто используемая операция, как интерактивный выбор файла, которая в обычном приложении решалась в одном методе, теперь требует создания цепочки из нескольких процедур, которые вызываются одна за другой через ОписаниеОповещения. Вот как это было с использованием модальных вызовов: 

Процедура КаталогНачалоВыбора(Элемент, СтандартнаяОбработка)
    
    ДиалогВыбораФайла = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.ВыборКаталога);
    
    ДиалогВыбораФайла.Каталог = ЭтотОбъект.Каталог;
    ДиалогВыбораФайла.Заголовок = "Выберите каталог";
    
    Если НЕ ДиалогВыбораФайла.Выбрать() Тогда
        Возврат;
    КонецЕсли;    
    
    ЭтотОбъект.Каталог = ДиалогВыбораФайла.Каталог;
    
КонецПроцедуры

Но как эту задачу решить на веб-клиенте? В поисковике не удалось найти готового универсального решения. Поискал в типовых, но там все разбросано по модулям и как-то запутано. Посмотрел пример в консоли СКД с диска ИТС для управляемых форм. Там тоже надо вычленять по кусочкам все шаги. Кроме того там применяется одна фича, которая позволяет открывать диалог выбора файла без установленного расширения работы с файлами. Но в общем случае эта хитрость не подойдет, так как она работает только для существующих файлов, насколько я понял. Поэтому написал процедуры, которые можно просто скопировать и использовать в будущем, не тратя время на то, чтобы вспоминать, как это работает.

Диалог выбора файла

Сразу приведу код, который получился после упрощения.

&НаКлиенте
Процедура КаталогНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    
    ДиалогВыбораФайла = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.ВыборКаталога);
    
    ДиалогВыбораФайла.Каталог = Объект.Каталог;
    ДиалогВыбораФайла.Заголовок = "Выберите каталог";
    
    ПараметрыСценария = Новый Структура;
    Оповещение = Новый ОписаниеОповещения("КаталогНачалоВыбораЗавершение", ЭтаФорма);
    ПараметрыСценария.Вставить("Оповещение_ПослеЗакрытияДиалогаВыбораФайла", Оповещение);
    ПараметрыСценария.Вставить("ДиалогВыбораФайла", ДиалогВыбораФайла);
                                
    ВыполнитьСценарийВыбораФайла(, ПараметрыСценария);
    
КонецПроцедуры

&НаКлиенте
Процедура КаталогНачалоВыбораЗавершение(Результат, ДополнительныеПараметры) Экспорт
    Если Результат = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    Объект.Каталог = Результат[0];
    
КонецПроцедуры

Я специально привел ранее вариант для обычных форм, чтобы проще было сравнивать. Код разбился на две примитивные процедуры и практически не изменился за счет метода ВыполнитьСценарийВыбораФайла(). Этот метод скрывает все рутинные асинхронные действия:
- подключает расширение по работе с файлами
- если расширение не подключено, то задает пользователю вопрос по его подключению
- начинает установку расширения, если пользователь подтвердит это действие
- открывает диалог выбора файла
- передает результаты выбора файла назад в прикладную процедуру КаталогНачалоВыбораЗавершение()

Далее приведу код этой служебной процедуры, написанной по принципу, из этой статьи. 

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

То есть вместо того, чтобы писать несколько процедур с труднопонимаемыми названиями в стиле ЗагрузитьФайлКонсолиПослеПодключенияРасширенияПослеПомещенияФайла(), вся последовательность действий описана в одной. Кроме того, можно заметить, что она универсальная и не содержит зависимостей от контекста формы. То есть ее можно перенести в другую форму простым копированием

Загрузка файлов с клиента на сервер

Постановка задачи: пусть требуется метод, который умеет помещать на сервер выбранный на клиенте файл. Если выбранный файл является каталогом, то необходимо поместить на сервер все файлы, содержащиеся в этом каталоге (подчиненные каталоги игнорировать).
Последовательность асинхронных действий:
- определить является ли файл каталогом
- если не является, то добавить его в массив помещаемых файлов
- если является, то найти все файлы этого каталога
- каждый из найденных файлов проверить является ли он каталогом. Если не является то добавить в массив помещаемых файлов (каждая итерация цикла обхода файлов является асинхронной, потому что вместо синхронного Файл.ЭтоФайл() необходимо использовать его аналог Файл.НачатьПроверкуЭтоФайл())
- поместить файлы на сервер
- вернуть результат помещения в прикладную процедуру, которая будет выполнять обработку файлов по какому-то алгоритму

Данная задача снова решается за три простых шага

&НаКлиенте
Процедура ОбработатьФайлы(Команда)

    ПараметрыСценария = Новый Структура;
    Оповещение = Новый ОписаниеОповещения("ПослеПомещенияФайлаНаСервер", ЭтаФорма);
    ПараметрыСценария.Вставить("Оповещение_ПослеПомещенияФайлаНаСервер", Оповещение);
    
    ВыполнитьСценарийЗагрузкиФайлаНаСервер(Объект.Каталог, ПараметрыСценария);
    
КонецПроцедуры

&НаКлиенте
Процедура ПослеПомещенияФайлаНаСервер(ПомещенныеФайлы, ДополнительныеПараметры) Экспорт
    
    ОбработатьФайлНаСервере(ПомещенныеФайлы);
    
КонецПроцедуры

&НаСервере
Процедура ОбработатьФайлНаСервере(ПомещенныеФайлы)
    
    // выполняем обработку результату по какому-нибудь алгоритму
    Для Каждого ОписаниеФайла Из ПомещенныеФайлы Цикл
        
        ИмяВременногоФайла = ПолучитьИмяВременногоФайла();
        Данные = ПолучитьИзВременногоХранилища(ОписаниеФайла.Хранение);
        Данные.Записать(ИмяВременногоФайла);
        
        Текст = Новый ТекстовыйДокумент;
        Текст.Прочитать(ИмяВременногоФайла);
        
        Объект.СодержимоеФайла = Текст.ПолучитьТекст();
        Прервать;
        
    КонецЦикла;
    
    
КонецПроцедуры

Все детали скрыты в процедуре ВыполнитьСценарийЗагрузкиФайлаНаСервер(), которая подходит как для файлов, так и для каталогов. При необходимости ее можно доработать, чтобы она покрывала больше случаев. 

Исходный код
&НаКлиенте
Процедура ВыполнитьСценарийЗагрузкиФайлаНаСервер(Результат = Неопределено, ПараметрыСценария = Неопределено) Экспорт
    
    НачатьОтсчетШагов(ПараметрыСценария);
    
    Оповещение = Новый ОписаниеОповещения("ВыполнитьСценарийЗагрузкиФайлаНаСервер", ЭтаФорма, ПараметрыСценария);
    
    // определим что на входе: файл или каталог
    Если ЭтотШагЕщеНеВыполнялся(ПараметрыСценария) Тогда
        ПараметрыСценария.Вставить("ИсходныйПомещаемыйФайл", Результат);
        Файл = Новый Файл(ПараметрыСценария.ИсходныйПомещаемыйФайл);
        Файл.НачатьПроверкуЭтоФайл(Оповещение);
        Возврат;
    КонецЕсли;
    
    // если передан каталог, то нужно найти все файлы, содеражщиеся в нем
    Если ЭтотШагЕщеНеВыполнялся(ПараметрыСценария) Тогда
        Если Результат = Истина Тогда // если это не каталог, то переходим к следующему шагу
            ПомещаемыеФайлы = Новый Массив;
            ПомещаемыеФайлы.Добавить(Новый Файл(ПараметрыСценария.ИсходныйПомещаемыйФайл));
            ВыполнитьОбработкуОповещения(Оповещение, ПомещаемыеФайлы);
            Возврат;
        Иначе
            // выполняем поиск всех файлов, содержащихся в переданном каталоге
            НачатьПоискФайлов(Оповещение, ПараметрыСценария.ИсходныйПомещаемыйФайл, "*.?*");
            Возврат;
        КонецЕсли;
    КонецЕсли;
    
    // проверяем, что найденные файлы не являются каталогами
    Если ЭтотШагЕщеНеВыполнялся(ПараметрыСценария) Тогда
        ПараметрыСценария.Вставить("НайденныеФайлы", Результат);
        ПараметрыСценария.Вставить("ПомещаемыеФайлы", Новый Массив);
        ПараметрыСценария.Вставить("ИндексПроверяемогоФайла", 0);
        Результат[ПараметрыСценария.ИндексПроверяемогоФайла].НачатьПроверкуЭтоФайл(Оповещение);
        Возврат;
        
    // асинхронная проверка каждого из найденных файлов
    ИначеЕсли ЭтоРезультатВыполненногоШага(ПараметрыСценария) Тогда
        
        Если Результат = Истина Тогда
            Файл = ПараметрыСценария.НайденныеФайлы[ПараметрыСценария.ИндексПроверяемогоФайла];
            ПараметрыСценария.ПомещаемыеФайлы.Добавить(Новый ОписаниеПередаваемогоФайла(Файл.ПолноеИмя, ""));
        КонецЕсли;
        
        Если ПараметрыСценария.НайденныеФайлы.Количество() > ПараметрыСценария.ИндексПроверяемогоФайла+1 Тогда
            ПараметрыСценария.ИндексПроверяемогоФайла = ПараметрыСценария.ИндексПроверяемогоФайла + 1;
            Файл = ПараметрыСценария.НайденныеФайлы[ПараметрыСценария.ИндексПроверяемогоФайла];
            Файл.НачатьПроверкуЭтоФайл(Оповещение);
            Возврат;
        КонецЕсли;
        
    КонецЕсли;
    
    // помещаем файлы на сервер
    Если ЭтотШагЕщеНеВыполнялся(ПараметрыСценария) Тогда
        
        ПомещаемыеФайлы = ПараметрыСценария.ПомещаемыеФайлы;
        Если ПомещаемыеФайлы.Количество() Тогда
            // передаем управление в прикладную процедуру
            НачатьПомещениеФайлов(ПараметрыСценария.Оповещение_ПослеПомещенияФайлаНаСервер, ПомещаемыеФайлы, , Ложь);    
        КонецЕсли;
        
        Возврат;
    КонецЕсли;
    
КонецПроцедуры


Файл для скачивания

К публикации прилагается пример, который можно использовать как шаблон для описанных операций. В нем реализованы несколько наиболее востребованных случаев: выбор существующего файла, выбор имени файла для сохранения, выбор каталога и множественный выбор. Для полноты картины приведены аналогичные операции для обычных форм. Тестировались процедуры на платфроме 8.3, на конфигурацях начиная с режима совместимости 8.2.13


 

Выбор файла выбрать файл выбор файла уф выбрать файл уф

См. также

Вставляем картинку из буфера обмена (платформа 1С 8.3.24)

Универсальные функции Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Задача: вставить картинку из буфера обмена на форму средствами платформы 1С.

1 стартмани

18.03.2024    2889    2    John_d    11    

56

GUID в 1С 8.3 - как с ними быть

Универсальные функции Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Пришлось помучиться с GUID-ами немного, решил поделиться опытом, мало ли кому пригодится.

12.02.2024    5042    atdonya    22    

51

Переоткрытие внешних обработок

Универсальные функции Платформа 1С v8.3 Бесплатно (free)

На заключительных этапах, когда идет отладка или доработка интерфейса, необходимо много раз переоткрыть внешний объект. Вот один из способов автоматизации этого.

30.11.2023    4101    ke.92@mail.ru    16    

62

Валидация JSON через XDTO (включая массивы)

WEB-интеграция Универсальные функции Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    9376    YA_418728146    6    

143

Печать непроведенных документов для УТ, КА, ERP. Настройка печати по пользователям, документам и печатным формам

Пакетная печать Печатные формы Адаптация типовых решений Универсальные функции Платформа 1С v8.3 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Абонемент ($m)

Расширение для программ 1С:Управление торговлей, 1С:Комплексная автоматизация, 1С:ERP, которое позволяет распечатывать печатные формы для непроведенных документов. Можно настроить, каким пользователям, какие конкретные формы документов разрешено печатать без проведения документа.

2 стартмани

22.08.2023    2229    25    progmaster    7    

3

Расширение: Быстрые отборы через буфер [Alt+C] Копировать список, [Alt+V] Вставить список, [Ctrl+C] Копировать из файлов

Инструментарий разработчика Универсальные функции Платформа 1С v8.3 Конфигурации 1cv8 1С:Розница 2 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Зарплата и Управление Персоналом 3.x Абонемент ($m)

Копирует в буфер значения из списков, из ячеек отчетов, таблиц, настроек списков, других отборов и вставляет в выбранную настройку отбора. Работает с Объект не найден. Работает как в одной так и между разными базами 1С. Использует комбинации [Alt+C] Копировать список, [Alt+V] Вставить список. Также для копирования данных используется стандартная [Ctrl+C] (например из открытого xls, mxl, doc и т.п. файла скопировать список наименований)

1 стартмани

13.10.2022    16350    142    sapervodichka    112    

130

Система контроля ведения учета [БСП]

Универсальные функции Механизмы типовых конфигураций БСП (Библиотека стандартных подсистем) Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

В данном материале рассмотрим типовой алгоритм подсистемы контроля учета БСП в конфигурациях на примерах.

18.07.2022    7355    quazare    8    

110
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Avt_Biz 25.07.18 22:25 Сейчас в теме
На Android не работает ! Требует установить расширение для работы с файлами, если установить расширение через код то идет ошибка об использовании модальных окон.
+
2. lenarha 5 03.08.18 19:40 Сейчас в теме
что в себе содержит процедура НачатьОтсчетШагов(ПараметрыСценария); Если ЭтотШагЕщеНеВыполнялся(ПараметрыСценария) Тогда

из текста не понятна логика
Igor253; shamahn; moemoe; sergey512; wowik; Gendelf; moonchild1; lonedog; AndreykO; +9
3. user1063327 11.12.19 12:17 Сейчас в теме
То чувство, когда статья про отказ от модальности, но в коде используют вызов модальной процедуры ПоказатьВопрос() ПоказатьВопрос(Оповещение, ТекстСообщения, РежимДиалогаВопрос.ДаНет);
Igor253; 1c_ssnik; +2
6. sinkawa 09.03.24 18:35 Сейчас в теме
(3) Это немодальный аналог модального метода глобального контекста "Вопрос".
Модальные методы не содержат в себе параметр типа "ОписаниеОповещения", поскольку приостанавливают выполнения кода до момента завершения своей работы.

Также выдержка из описания метода "Вопрос" в Синтакс-помощнике:
Если для конфигурации свойство РежимИспользованияМодальности установлено в НеИспользовать, следует использовать метод ПоказатьВопрос.
+
4. Aleksandr_prof 192 11.06.21 12:27 Сейчас в теме
А можете объяснить, в чём тут асинхронность и для чего она нужна в нашем случае?
1c_ssnik; +1
5. CaSH_2004 372 31.07.21 23:25 Сейчас в теме
Описанный пример не рабочий т.к. код приведен не полностью. Отсутствуют:
1. НачатьОтсчетШагов()
2. ЭтотШагЕщеНеВыполнялся()
Igor253; @lexandr; 1c_ssnik; +3
7. sinkawa 09.03.24 18:38 Сейчас в теме
(5) Автор статьи в тексте оставил ссылку на оригинальную статью, по которой писал свой метод "ВыполнитьСценарийЗагрузкиФайлаНаСервер". Там описаны эти методы.
+
Оставьте свое сообщение