Как открыть диалог выбора файла в 1С

· 9 мин

Содержание

Диалог выбора файла в 1С открывают на клиенте: создают объект Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие) и вызывают у него Показать(ОписаниеОповещения) или, начиная с платформы 8.3.18, Ждать Диалог.ВыбратьАсинх(). Синхронный Выбрать() в современных конфигурациях не сработает: там запрещены модальные окна.

Типичная ситуация: разработчик делает обработку загрузки прайса из Excel, пишет Если Диалог.Выбрать() Тогда по старому примеру из интернета и получает ошибку Использование модальных окон в данном режиме запрещено. Исправляется это заменой одной строки, но в веб-клиенте и при передаче файла на сервер есть свои подводные камни.

Как открыть диалог выбора файла: минимальный рабочий код

Весь код с диалогом выполняется только в клиентском контексте — в процедурах с директивой &НаКлиенте. На сервере у пользователя нет экрана, поэтому объект ДиалогВыбораФайла там недоступен.

Вариант 1. Показать() с описанием оповещения

Подходит для любой платформы 8.3 начиная с 8.3.3 и для конфигураций в режиме совместимости без модальности.

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

    Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    Диалог.Заголовок = "Выберите файл для загрузки";
    Диалог.Фильтр = "Таблицы Excel (*.xlsx;*.xls)|*.xlsx;*.xls|Все файлы (*.*)|*.*";
    Диалог.МножественныйВыбор = Ложь;

    Оповещение = Новый ОписаниеОповещения("ВыбратьФайлЗавершение", ЭтотОбъект);
    Диалог.Показать(Оповещение);

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

&НаКлиенте
Процедура ВыбратьФайлЗавершение(ВыбранныеФайлы, ДополнительныеПараметры) Экспорт

    Если ВыбранныеФайлы = Неопределено Тогда
        Возврат; // пользователь нажал «Отмена»
    КонецЕсли;

    ПутьКФайлу = ВыбранныеФайлы[0];
    Сообщить("Выбран файл: " + ПутьКФайлу);

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

Три правила, без которых код не заработает:

  1. 🔹 Процедура-обработчик объявлена с ключевым словом Экспорт, иначе платформа её не найдёт.
  2. 🔹 У обработчика два параметра: результат и дополнительные параметры.
  3. 🔹 Результат — массив путей или Неопределено при отмене. Проверка на Неопределено обязательна.

Вариант 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];
КонецЕсли;

Открытие диалога из поля формы по кнопке «…»

Чаще пользователю нужна не отдельная команда, а реквизит формы «Путь к файлу» с кнопкой выбора. Делается так:

  1. Добавьте реквизит формы типа Строка и выведите его полем ввода.
  2. В свойствах поля включите КнопкаВыбора.
  3. Создайте обработчик события НачалоВыбора.
  4. В обработчике отключите стандартную обработку и откройте диалог.
&НаКлиенте
Асинх Процедура ПутьКФайлуНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)

    СтандартнаяОбработка = Ложь;

    Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    Диалог.ПолноеИмяФайла = ПутьКФайлу; // откроется с текущим значением
    Диалог.Фильтр = "Файлы XML (*.xml)|*.xml";

    Результат = Ждать Диалог.ВыбратьАсинх();
    Если Результат <> Неопределено Тогда
        ПутьКФайлу = Результат[0];
    КонецЕсли;

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

СтандартнаяОбработка = Ложь ставьте до Ждать. После первого Ждать управление уже вернулось платформе, и присваивание ничего не отменит.

Диалог выбора файла в веб-клиенте: расширение работы с файлами

В браузере у страницы нет доступа к файловой системе компьютера. Поэтому ДиалогВыбораФайла в веб-клиенте работает только при подключённом расширении работы с файлами. Без него вызов закончится ошибкой.

Есть два пути.

Путь А. Подключить расширение

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

    Подключено = Ждать ПодключитьРасширениеРаботыСФайламиАсинх();
    Если Не Подключено Тогда
        Ждать УстановитьРасширениеРаботыСФайламиАсинх();
        Подключено = Ждать ПодключитьРасширениеРаботыСФайламиАсинх();
    КонецЕсли;

    Если Не Подключено Тогда
        Сообщить("Расширение работы с файлами не установлено");
        Возврат;
    КонецЕсли;

    Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    Результат = Ждать Диалог.ВыбратьАсинх();
    // дальше как в тонком клиенте

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

Для платформ до 8.3.18 то же самое делают через НачатьПодключениеРасширенияРаботыСФайлами и НачатьУстановкуРасширенияРаботыСФайлами с описаниями оповещения. В тонком клиенте расширение всегда подключено, проверка вернёт Истина сразу.

Путь Б. Обойтись без расширения

Если файл нужно только загрузить на сервер, расширение не требуется. Метод НачатьПомещениеФайла с параметром Интерактивно = Истина открывает стандартное окно выбора браузера и сразу кладёт файл во временное хранилище. Пример — в следующем разделе.

ЗадачаБез расширенияС расширением
Выбрать и загрузить один файл✅ НачатьПомещениеФайла✅
Получить полный путь к файлу на диске❌✅
Выбрать каталог❌✅
Прочитать файл на клиенте без сервера❌✅

Как загрузить выбранный файл в двоичные данные

Путь C:\Users\buh\Прайс.xlsx на сервере бесполезен: сервер 1С — другой компьютер, такого файла там нет. Файл надо передать через временное хранилище.

Универсальный способ: НачатьПомещениеФайла

Работает и в тонком, и в веб-клиенте без расширения:

&НаКлиенте
Процедура ЗагрузитьФайл(Команда)

    Оповещение = Новый ОписаниеОповещения("ЗагрузитьФайлЗавершение", ЭтотОбъект);
    НачатьПомещениеФайла(Оповещение, , "", Истина, УникальныйИдентификатор);

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

&НаКлиенте
Процедура ЗагрузитьФайлЗавершение(Результат, Адрес, ВыбранноеИмяФайла, ДополнительныеПараметры) Экспорт

    Если Не Результат Тогда
        Возврат; // отмена
    КонецЕсли;

    ОбработатьФайлНаСервере(Адрес, ВыбранноеИмяФайла);

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

&НаСервере
Процедура ОбработатьФайлНаСервере(Адрес, ИмяФайла)

    ДвоичныеДанные = ПолучитьИзВременногоХранилища(Адрес);
    УдалитьИзВременногоХранилища(Адрес);

    ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xlsx");
    ДвоичныеДанные.Записать(ИмяВременногоФайла);

    // ... чтение файла, например через ТабличныйДокумент.Прочитать()

    УдалитьФайлы(ИмяВременногоФайла);

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

Параметр УникальныйИдентификатор формы привязывает данные хранилища к форме: при её закрытии они удалятся сами. Без него данные живут до конца сеанса.

Если путь уже выбран диалогом

В тонком клиенте можно прочитать файл прямо по пути и отправить на сервер:

ДД = Новый ДвоичныеДанные(ПутьКФайлу);
Адрес = ПоместитьВоВременноеХранилище(ДД, УникальныйИдентификатор);
ОбработатьФайлНаСервере(Адрес, ПутьКФайлу);

Для файлов в десятки мегабайт этот вариант хуже: весь файл целиком попадает в память клиента.

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

Включите МножественныйВыбор = Истина и обойдите массив результата. Каждый файл отправляйте в хранилище отдельно и собирайте адреса в массив, а на сервер передавайте его одним вызовом:

Адреса = Новый Массив;
Для Каждого Путь Из ВыбранныеФайлы Цикл
    ДД = Новый ДвоичныеДанные(Путь);
    Адреса.Добавить(ПоместитьВоВременноеХранилище(ДД, УникальныйИдентификатор));
КонецЦикла;
ОбработатьФайлыНаСервере(Адреса);

Один серверный вызов вместо десяти заметно быстрее на медленном канале: каждый вызов сервера — это отдельный сетевой обмен.

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

Сохранение файла через диалог

Обратная задача: сформировать файл на сервере и дать пользователю выбрать, куда его положить.

Через НачатьПолучениеФайлов

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

    Адрес = СформироватьФайлНаСервере();

    ПолучаемыеФайлы = Новый Массив;
    ПолучаемыеФайлы.Добавить(Новый ОписаниеПередаваемогоФайла("Выгрузка.xml", Адрес));

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

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

&НаКлиенте
Процедура ВыгрузитьФайлЗавершение(ПолученныеФайлы, ДополнительныеПараметры) Экспорт
    // ПолученныеФайлы = Неопределено, если пользователь отменил сохранение
КонецПроцедуры

&НаСервере
Функция СформироватьФайлНаСервере()

    Текст = Новый ТекстовыйДокумент;
    Текст.УстановитьТекст("<root/>");
    ИмяФайла = ПолучитьИмяВременногоФайла("xml");
    Текст.Записать(ИмяФайла, КодировкаТекста.UTF8);

    Адрес = ПоместитьВоВременноеХранилище(Новый ДвоичныеДанные(ИмяФайла), УникальныйИдентификатор);
    УдалитьФайлы(ИмяФайла);
    Возврат Адрес;

КонецФункции

С Интерактивно = Истина платформа сама покажет окно сохранения. В веб-клиенте без расширения файл уйдёт в загрузки браузера.

Через ДиалогВыбораФайла в режиме сохранения

Когда нужен свой заголовок, фильтр и имя по умолчанию:

Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Сохранение);
Диалог.Заголовок = "Сохранить реестр";
Диалог.Фильтр = "CSV (*.csv)|*.csv";
Диалог.ПолноеИмяФайла = "Реестр_" + Формат(ТекущаяДата(), "ДФ=yyyyMMdd") + ".csv";

Результат = Ждать Диалог.ВыбратьАсинх();
Если Результат <> Неопределено Тогда
    ДД = ПолучитьИзВременногоХранилища(Адрес);
    ДД.Записать(Результат[0]);
КонецЕсли;

Здесь Адрес — адрес временного хранилища, полученный с сервера заранее. Запись по пути Результат[0] выполняется на клиенте, поэтому в веб-клиенте нужен подключённый модуль расширения.

Ошибки при открытии диалога и их перехват

Диагностика: выберите симптом

Как перехватить исключение

В асинхронной процедуре Попытка охватывает и Ждать, поэтому ошибку чтения или записи файла ловят обычным способом:

Попытка
    Результат = Ждать Диалог.ВыбратьАсинх();
    Если Результат = Неопределено Тогда
        Возврат;
    КонецЕсли;
    ДД = Новый ДвоичныеДанные(Результат[0]);
Исключение
    Инфо = ИнформацияОбОшибке();
    Сообщить("Не удалось прочитать файл: " + КраткоеПредставлениеОшибки(Инфо));
    ЗаписатьОшибкуВЖурнал(ПодробноеПредставлениеОшибки(Инфо));
КонецПопытки;

Процедура записи в журнал — серверная, потому что в тонком и веб-клиенте метод ЗаписьЖурналаРегистрации недоступен:

&НаСервереБезКонтекста
Процедура ЗаписатьОшибкуВЖурнал(ТекстОшибки)
    ЗаписьЖурналаРегистрации("Загрузка файла", УровеньЖурналаРегистрации.Ошибка, , , ТекстОшибки);
КонецПроцедуры

Пользователю показывайте краткое описание, подробное — в журнал регистрации. Частые причины исключения при чтении: файл открыт в Excel и заблокирован, нет прав на папку, путь указывает на сетевой диск, который отключился.

Частые вопросы

Можно ли открыть диалог выбора файла на сервере?
Нет. Окно показывается пользователю, поэтому ДиалогВыбораФайла доступен только в клиентском контексте. На сервер передают уже выбранные данные через временное хранилище.
Как получить имя файла без пути?
Создайте Новый Файл(ПолныйПуть) и возьмите свойство Имя (с расширением) или ИмяБезРасширения. Свойство Расширение вернёт расширение с точкой.
Почему в веб-клиенте не виден полный путь к файлу?
Браузер из соображений безопасности не сообщает странице путь на диске. Полный путь доступен только при подключённом расширении работы с файлами.
Как запомнить последнюю папку, из которой выбирали файл?
Сохраните значение в настройках пользователя через ОбщегоНазначенияВызовСервера.ХранилищеОбщихНастроекСохранить (в конфигурациях на БСП) или в реквизит формы с автосохранением, а перед открытием диалога подставьте его в свойство Каталог.
Как не дать пользователю загрузить слишком большой файл?
Фильтр диалога размер не ограничивает. Проверьте на сервере ДвоичныеДанные.Размер() — метод возвращает размер в байтах — и откажите с понятным сообщением, если превышен лимит, например 20 МБ (20 971 520 байт).