Как открыть диалог выбора файла в 1С
Содержание
Диалог выбора файла в 1С открывают на клиенте: создают объект Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие) и вызывают у него Показать(ОписаниеОповещения) или, начиная с платформы 8.3.18, Ждать Диалог.ВыбратьАсинх(). Синхронный Выбрать() в современных конфигурациях не сработает: там запрещены модальные окна.
Типичная ситуация: разработчик делает обработку загрузки прайса из Excel, пишет Если Диалог.Выбрать() Тогда по старому примеру из интернета и получает ошибку Использование модальных окон в данном режиме запрещено. Исправляется это заменой одной строки, но в веб-клиенте и при передаче файла на сервер есть свои подводные камни.
Как открыть диалог выбора файла: минимальный рабочий код
Весь код с диалогом выполняется только в клиентском контексте — в процедурах с директивой &НаКлиенте. На сервере у пользователя нет экрана, поэтому объект ДиалогВыбораФайла там недоступен.
Вариант 1. Показать() с описанием оповещения
Подходит для любой платформы 8.3 начиная с 8.3.3 и для конфигураций в режиме совместимости без модальности.
&НаКлиенте
Процедура ВыбратьФайл(Команда)
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Диалог.Заголовок = "Выберите файл для загрузки";
Диалог.Фильтр = "Таблицы Excel (*.xlsx;*.xls)|*.xlsx;*.xls|Все файлы (*.*)|*.*";
Диалог.МножественныйВыбор = Ложь;
Оповещение = Новый ОписаниеОповещения("ВыбратьФайлЗавершение", ЭтотОбъект);
Диалог.Показать(Оповещение);
КонецПроцедуры
&НаКлиенте
Процедура ВыбратьФайлЗавершение(ВыбранныеФайлы, ДополнительныеПараметры) Экспорт
Если ВыбранныеФайлы = Неопределено Тогда
Возврат; // пользователь нажал «Отмена»
КонецЕсли;
ПутьКФайлу = ВыбранныеФайлы[0];
Сообщить("Выбран файл: " + ПутьКФайлу);
КонецПроцедуры
Три правила, без которых код не заработает:
- 🔹 Процедура-обработчик объявлена с ключевым словом
Экспорт, иначе платформа её не найдёт. - 🔹 У обработчика два параметра: результат и дополнительные параметры.
- 🔹 Результат — массив путей или
Неопределенопри отмене. Проверка наНеопределенообязательна.
Вариант 2. ВыбратьАсинх() и Ждать
С платформы 8.3.18 появились асинхронные процедуры. Код становится линейным, без отдельного обработчика:
&НаКлиенте
Асинх Процедура ВыбратьФайл(Команда)
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Диалог.Фильтр = "Текстовые файлы (*.txt;*.csv)|*.txt;*.csv";
ВыбранныеФайлы = Ждать Диалог.ВыбратьАсинх();
Если ВыбранныеФайлы = Неопределено Тогда
Возврат;
КонецЕсли;
Для Каждого Путь Из ВыбранныеФайлы Цикл
Сообщить(Путь);
КонецЦикла;
КонецПроцедуры
Асинх и Ждать доступны, только если в свойствах конфигурации режим совместимости не ниже 8.3.18. Проверить: корень дерева конфигурации → Свойства → Режим совместимости.
Какой способ выбрать
| Способ | Платформа | Когда брать | Ограничения |
|---|---|---|---|
Выбрать() | любая | старые конфигурации с разрешённой модальностью | не работает при «Не использовать» модальность |
Показать() | 8.3.3 и новее | типовые решения, поддержка старых релизов | код дробится на две процедуры |
ВыбратьАсинх() | 8.3.18 и новее | новые разработки | нужен режим совместимости не ниже 8.3.18 |
Режимы и свойства объекта ДиалогВыбораФайла
Режим задают при создании объекта, сменить его потом можно через свойство Режим. Значений три:
- 📂
РежимДиалогаВыбораФайла.Открытие— выбор существующего файла. - 💾
РежимДиалогаВыбораФайла.Сохранение— ввод имени для нового файла, платформа спросит о перезаписи существующего. - 🗂
РежимДиалогаВыбораФайла.ВыборКаталога— выбор папки, а не файла.
Свойства, которые нужны на практике
| Свойство | Что задаёт | Пример |
|---|---|---|
Заголовок | текст в шапке окна | "Загрузка выписки" |
Фильтр | типы файлов в выпадающем списке | "XML (*.xml)|*.xml" |
ИндексФильтра | какой фильтр выбран при открытии (с нуля) | 0 |
Каталог | папка, открытая при старте | "C:\Обмен" |
ПолноеИмяФайла | имя файла по умолчанию / выбранный путь | "Прайс.xlsx" |
МножественныйВыбор | разрешить выбор нескольких файлов | Истина |
ВыбранныеФайлы | массив выбранных путей | читается после выбора |
ПроверятьСуществованиеФайла | не давать ввести имя несуществующего файла | Истина |
ПредварительныйПросмотр | панель предпросмотра в окне | Ложь |
Синтаксис фильтра
Фильтр — строка из пар «описание|маска», разделённых вертикальной чертой. Несколько масок в одной паре разделяют точкой с запятой:
Диалог.Фильтр = "Документы (*.docx;*.pdf)|*.docx;*.pdf"
+ "|Изображения (*.png;*.jpg)|*.png;*.jpg"
+ "|Все файлы (*.*)|*.*";
Диалог.ИндексФильтра = 1; // откроется с фильтром «Изображения»
Если забыть маску у одной из пар, описания и маски сдвинутся, и в списке типов окажется мусор. Пересчитайте вертикальные черты: при двух парах их три, при трёх — пять.
Выбор каталога
В режиме ВыборКаталога путь к папке возвращается первым элементом массива в обработчике, а также записывается в свойство Каталог:
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.ВыборКаталога);
Диалог.Заголовок = "Куда выгрузить файлы";
Каталог = Ждать Диалог.ВыбратьАсинх();
Если Каталог <> Неопределено Тогда
ПапкаВыгрузки = Каталог[0];
КонецЕсли;
Открытие диалога из поля формы по кнопке «…»
Чаще пользователю нужна не отдельная команда, а реквизит формы «Путь к файлу» с кнопкой выбора. Делается так:
- Добавьте реквизит формы типа
Строкаи выведите его полем ввода. - В свойствах поля включите
КнопкаВыбора. - Создайте обработчик события
НачалоВыбора. - В обработчике отключите стандартную обработку и откройте диалог.
&НаКлиенте
Асинх Процедура ПутьКФайлуНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Диалог.ПолноеИмяФайла = ПутьКФайлу; // откроется с текущим значением
Диалог.Фильтр = "Файлы XML (*.xml)|*.xml";
Результат = Ждать Диалог.ВыбратьАсинх();
Если Результат <> Неопределено Тогда
ПутьКФайлу = Результат[0];
КонецЕсли;
КонецПроцедуры
СтандартнаяОбработка = Ложь ставьте до Ждать. После первого Ждать управление уже вернулось платформе, и присваивание ничего не отменит.
Диалог выбора файла в веб-клиенте: расширение работы с файлами
В браузере у страницы нет доступа к файловой системе компьютера. Поэтому ДиалогВыбораФайла в веб-клиенте работает только при подключённом расширении работы с файлами. Без него вызов закончится ошибкой.
Есть два пути.
Путь А. Подключить расширение
&НаКлиенте
Асинх Процедура ВыбратьФайлВебКлиент(Команда)
Подключено = Ждать ПодключитьРасширениеРаботыСФайламиАсинх();
Если Не Подключено Тогда
Ждать УстановитьРасширениеРаботыСФайламиАсинх();
Подключено = Ждать ПодключитьРасширениеРаботыСФайламиАсинх();
КонецЕсли;
Если Не Подключено Тогда
Сообщить("Расширение работы с файлами не установлено");
Возврат;
КонецЕсли;
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Результат = Ждать Диалог.ВыбратьАсинх();
// дальше как в тонком клиенте
КонецПроцедуры
Для платформ до 8.3.18 то же самое делают через НачатьПодключениеРасширенияРаботыСФайлами и НачатьУстановкуРасширенияРаботыСФайлами с описаниями оповещения. В тонком клиенте расширение всегда подключено, проверка вернёт Истина сразу.
Путь Б. Обойтись без расширения
Если файл нужно только загрузить на сервер, расширение не требуется. Метод НачатьПомещениеФайла с параметром Интерактивно = Истина открывает стандартное окно выбора браузера и сразу кладёт файл во временное хранилище. Пример — в следующем разделе.
| Задача | Без расширения | С расширением |
|---|---|---|
| Выбрать и загрузить один файл | ✅ НачатьПомещениеФайла | ✅ |
| Получить полный путь к файлу на диске | ❌ | ✅ |
| Выбрать каталог | ❌ | ✅ |
| Прочитать файл на клиенте без сервера | ❌ | ✅ |
Как загрузить выбранный файл в двоичные данные
Путь C:\Users\buh\Прайс.xlsx на сервере бесполезен: сервер 1С — другой компьютер, такого файла там нет. Файл надо передать через временное хранилище.
Универсальный способ: НачатьПомещениеФайла
Работает и в тонком, и в веб-клиенте без расширения:
&НаКлиенте
Процедура ЗагрузитьФайл(Команда)
Оповещение = Новый ОписаниеОповещения("ЗагрузитьФайлЗавершение", ЭтотОбъект);
НачатьПомещениеФайла(Оповещение, , "", Истина, УникальныйИдентификатор);
КонецПроцедуры
&НаКлиенте
Процедура ЗагрузитьФайлЗавершение(Результат, Адрес, ВыбранноеИмяФайла, ДополнительныеПараметры) Экспорт
Если Не Результат Тогда
Возврат; // отмена
КонецЕсли;
ОбработатьФайлНаСервере(Адрес, ВыбранноеИмяФайла);
КонецПроцедуры
&НаСервере
Процедура ОбработатьФайлНаСервере(Адрес, ИмяФайла)
ДвоичныеДанные = ПолучитьИзВременногоХранилища(Адрес);
УдалитьИзВременногоХранилища(Адрес);
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xlsx");
ДвоичныеДанные.Записать(ИмяВременногоФайла);
// ... чтение файла, например через ТабличныйДокумент.Прочитать()
УдалитьФайлы(ИмяВременногоФайла);
КонецПроцедуры
Параметр УникальныйИдентификатор формы привязывает данные хранилища к форме: при её закрытии они удалятся сами. Без него данные живут до конца сеанса.
Если путь уже выбран диалогом
В тонком клиенте можно прочитать файл прямо по пути и отправить на сервер:
ДД = Новый ДвоичныеДанные(ПутьКФайлу);
Адрес = ПоместитьВоВременноеХранилище(ДД, УникальныйИдентификатор);
ОбработатьФайлНаСервере(Адрес, ПутьКФайлу);
Для файлов в десятки мегабайт этот вариант хуже: весь файл целиком попадает в память клиента.
Как загрузить сразу несколько файлов
Включите МножественныйВыбор = Истина и обойдите массив результата. Каждый файл отправляйте в хранилище отдельно и собирайте адреса в массив, а на сервер передавайте его одним вызовом:
Адреса = Новый Массив;
Для Каждого Путь Из ВыбранныеФайлы Цикл
ДД = Новый ДвоичныеДанные(Путь);
Адреса.Добавить(ПоместитьВоВременноеХранилище(ДД, УникальныйИдентификатор));
КонецЦикла;
ОбработатьФайлыНаСервере(Адреса);
Один серверный вызов вместо десяти заметно быстрее на медленном канале: каждый вызов сервера — это отдельный сетевой обмен.
В типовых конфигурациях на БСП удобнее вызывать готовые процедуры модуля ФайловаяСистемаКлиент (например, ЗагрузитьФайл). Они сами решают вопрос с расширением в веб-клиенте.
Сохранение файла через диалог
Обратная задача: сформировать файл на сервере и дать пользователю выбрать, куда его положить.
Через НачатьПолучениеФайлов
&НаКлиенте
Процедура ВыгрузитьФайл(Команда)
Адрес = СформироватьФайлНаСервере();
ПолучаемыеФайлы = Новый Массив;
ПолучаемыеФайлы.Добавить(Новый ОписаниеПередаваемогоФайла("Выгрузка.xml", Адрес));
Оповещение = Новый ОписаниеОповещения("ВыгрузитьФайлЗавершение", ЭтотОбъект);
НачатьПолучениеФайлов(Оповещение, ПолучаемыеФайлы, , Истина);
КонецПроцедуры
&НаКлиенте
Процедура ВыгрузитьФайлЗавершение(ПолученныеФайлы, ДополнительныеПараметры) Экспорт
// ПолученныеФайлы = Неопределено, если пользователь отменил сохранение
КонецПроцедуры
&НаСервере
Функция СформироватьФайлНаСервере()
Текст = Новый ТекстовыйДокумент;
Текст.УстановитьТекст("<root/>");
ИмяФайла = ПолучитьИмяВременногоФайла("xml");
Текст.Записать(ИмяФайла, КодировкаТекста.UTF8);
Адрес = ПоместитьВоВременноеХранилище(Новый ДвоичныеДанные(ИмяФайла), УникальныйИдентификатор);
УдалитьФайлы(ИмяФайла);
Возврат Адрес;
КонецФункции
С Интерактивно = Истина платформа сама покажет окно сохранения. В веб-клиенте без расширения файл уйдёт в загрузки браузера.
Через ДиалогВыбораФайла в режиме сохранения
Когда нужен свой заголовок, фильтр и имя по умолчанию:
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Сохранение);
Диалог.Заголовок = "Сохранить реестр";
Диалог.Фильтр = "CSV (*.csv)|*.csv";
Диалог.ПолноеИмяФайла = "Реестр_" + Формат(ТекущаяДата(), "ДФ=yyyyMMdd") + ".csv";
Результат = Ждать Диалог.ВыбратьАсинх();
Если Результат <> Неопределено Тогда
ДД = ПолучитьИзВременногоХранилища(Адрес);
ДД.Записать(Результат[0]);
КонецЕсли;
Здесь Адрес — адрес временного хранилища, полученный с сервера заранее. Запись по пути Результат[0] выполняется на клиенте, поэтому в веб-клиенте нужен подключённый модуль расширения.
Ошибки при открытии диалога и их перехват
Выбрать() при режиме модальности «Не использовать». Замените на Показать() или ВыбратьАсинх().ПодключитьРасширениеРаботыСФайламиАсинх() или используйте НачатьПомещениеФайла.Экспорт, имя в ОписаниеОповещения написано с опечаткой или указан не тот модуль во втором параметре.Неопределено, а пользователь нажал «Отмена». Либо обращаются к [1] при одном выбранном файле.Как перехватить исключение
В асинхронной процедуре Попытка охватывает и Ждать, поэтому ошибку чтения или записи файла ловят обычным способом:
Попытка
Результат = Ждать Диалог.ВыбратьАсинх();
Если Результат = Неопределено Тогда
Возврат;
КонецЕсли;
ДД = Новый ДвоичныеДанные(Результат[0]);
Исключение
Инфо = ИнформацияОбОшибке();
Сообщить("Не удалось прочитать файл: " + КраткоеПредставлениеОшибки(Инфо));
ЗаписатьОшибкуВЖурнал(ПодробноеПредставлениеОшибки(Инфо));
КонецПопытки;
Процедура записи в журнал — серверная, потому что в тонком и веб-клиенте метод ЗаписьЖурналаРегистрации недоступен:
&НаСервереБезКонтекста
Процедура ЗаписатьОшибкуВЖурнал(ТекстОшибки)
ЗаписьЖурналаРегистрации("Загрузка файла", УровеньЖурналаРегистрации.Ошибка, , , ТекстОшибки);
КонецПроцедуры
Пользователю показывайте краткое описание, подробное — в журнал регистрации. Частые причины исключения при чтении: файл открыт в Excel и заблокирован, нет прав на папку, путь указывает на сетевой диск, который отключился.
Частые вопросы
Можно ли открыть диалог выбора файла на сервере?
ДиалогВыбораФайла доступен только в клиентском контексте. На сервер передают уже выбранные данные через временное хранилище.Как получить имя файла без пути?
Новый Файл(ПолныйПуть) и возьмите свойство Имя (с расширением) или ИмяБезРасширения. Свойство Расширение вернёт расширение с точкой.Почему в веб-клиенте не виден полный путь к файлу?
Как запомнить последнюю папку, из которой выбирали файл?
ОбщегоНазначенияВызовСервера.ХранилищеОбщихНастроекСохранить (в конфигурациях на БСП) или в реквизит формы с автосохранением, а перед открытием диалога подставьте его в свойство Каталог.Как не дать пользователю загрузить слишком большой файл?
ДвоичныеДанные.Размер() — метод возвращает размер в байтах — и откажите с понятным сообщением, если превышен лимит, например 20 МБ (20 971 520 байт).