Почему не отображаются файлы Excel при открытии диалога выбора в 1С и как это исправить?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке механизмов импорта данных из внешних источников программисты часто сталкиваются с задачей интерактивного выбора файла пользователем. В платформе 1С:Предприятие для этих целей предназначен стандартный объект ДиалогВыбораФайла. Однако при его настройке легко допустить синтаксическую ошибку, из-за которой нужные файлы (например, таблицы Excel с расширениями .xls или .xlsx) попросту перестают отображаться в открывшемся окне проводника.

В этой статье мы подробно разберем, почему возникает подобная проблема, детально проанализируем синтаксис настройки фильтров диалога, рассмотрим опасности «ленивых» масок, а также перепишем устаревший модальный код под современные стандарты платформы 1С:Предприятие 8.3 с использованием асинхронности и инструментов Библиотеки Стандартных Подсистем (БСП).

Выясняем причину: синтаксическая ошибка в свойстве Фильтр

Посмотрим на исходный код, который вызвал затруднения у автора темы:


ДиалогОткрытия = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
ДиалогОткрытия.ПолноеИмяФайла = "";
ДиалогОткрытия.Фильтр = "Файлы Excel (*.xls|*.xlsx)|*.xl*";

Проблема кроется в строке инициализации свойства Фильтр. Давайте разберем, как именно платформа 1С интерпретирует эту строку. Свойство Фильтр требует строгого соблюдения формата:

"Текстовое описание 1|Маска 1|Текстовое описание 2|Маска 2|..."

В качестве разделителя между понятным пользователю описанием формата и реальной системной маской расширений платформа использует строго символ вертикальной черты (|). Символ вертикальной черты нельзя использовать внутри самого текстового описания для разделения расширений.

В исходном примере разработчик написал:

"Файлы Excel (*.xls|*.xlsx)|*.xl*"

Платформа обработала эту строку следующим образом:

  1. Первое текстовое описание: "Файлы Excel (*.xls" (все, что идет до первой вертикальной черты).
  2. Первая системная маска поиска: "*.xlsx)" (все, что идет между первой и второй вертикальной чертой). В результате операционная система пыталась найти файлы, чье расширение буквально заканчивается на символ закрывающей скобки. Естественно, таких файлов в каталоге не существовало, и папка визуально казалась пустой.
  3. Второе текстовое описание: "*.xl*".
  4. Вторая системная маска поиска: пустая строка (так как для нее не было пары после следующего разделителя).

Таким образом, из-за одной лишней вертикальной черты внутри скобок логика работы фильтра полностью нарушилась.

Правильное построение фильтра файлов

Выяснив причину, исправим синтаксис. Для того чтобы в рамках одного фильтра указать несколько допустимых расширений (и .xls, и .xlsx), в системной маске необходимо использовать в качестве разделителя точку с запятой (;). При этом в текстовом описании для пользователя мы можем перечислить форматы через запятую.

Рассмотрим рабочий и корректный вариант настройки фильтра:

ДиалогОткрытия.Фильтр = "Файлы Excel (*.xls, *.xlsx)|*.xls;*.xlsx";

Важное предупреждение: Обратите внимание, что в системной маске после точки с запятой (*.xls;*.xlsx) нельзя ставить пробелы. Если написать "*.xls; *.xlsx", то на некоторых операционных системах или при работе в веб-клиенте маска отработает некорректно, и файлы второго типа не будут отображены.

Опасность использования «ленивой» маски *.xl*

В предложенном на форуме быстром решении фигурировала маска вида "*.xl*". На первый взгляд это кажется удобным: символ звездочки (*) заменяет любую последовательность символов, а значит, под фильтр гарантированно попадут и старый формат .xls, и новый .xlsx.

Однако проанализируем потенциальные риски использования такой «ленивой» маски. Символ * подставит абсолютно любые окончания. В результате в диалоговом окне пользователь увидит:

Если программный код чтения файла (например, через COM-соединение Excel.Application, чтение ADO или встроенный объект 1С ТабличныйДокумент) жестко рассчитывает только на определенную структуру и формат (исключительно .xls или .xlsx), выбор пользователем «нестандартного» файла приведет к аварийному завершению работы алгоритма и ошибкам выполнения. Поэтому хорошей практикой является явное и строгое указание только тех расширений, с которыми гарантированно умеет работать ваша обработка.

Переход к современным стандартам: избавляемся от модальности

Посмотрим на исходный код автора темы еще раз. В нем используется метод ДиалогОткрытия.Выбрать(). Это модальный метод, который полностью блокирует интерфейс программы до тех пор, пока пользователь не закроет диалоговое окно.

В современных конфигурациях на платформе 1С:Предприятие 8.3 в свойствах конфигурации по умолчанию включен режим «Использовать модальность = Не использовать». Это необходимо для обеспечения кроссплатформенности, работы в веб-клиенте и на мобильных устройствах, где модальные окна заблокированы на уровне браузеров или операционных систем. При попытке выполнить метод Выбрать() в таком режиме система выдаст ошибку времени выполнения.

Перепишем наш алгоритм по-современному. Начиная с версии платформы 1С:Предприятие 8.3.18, разработчикам доступен асинхронный подход с использованием ключевых слов Асинх и Ждать.

Разберем готовый асинхронный код:


&НаКлиенте
Асинх Процедура ЗагружаемыйФайлНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    
    // Шаг 1. Отменяем стандартное поведение платформы при выборе в поле ввода
    СтандартнаяОбработка = Ложь;
    
    // Шаг 2. Инициализируем диалог выбора файла
    ДиалогОткрытия = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    ДиалогОткрытия.ПолноеИмяФайла = "";
    ДиалогОткрытия.Фильтр = "Файлы Excel (*.xls; *.xlsx)|*.xls;*.xlsx";
    ДиалогОткрытия.МножественныйВыбор = Ложь;
    ДиалогОткрытия.Заголовок = "Выберите файл Excel для загрузки";
    
    // Шаг 3. Вызываем асинхронный метод выбора файла и ожидаем результат
    ВыбранныеФайлы = Ждать ДиалогОткрытия.ВыбратьАсинх();
    
    // Шаг 4. Обрабатываем результат интерактивного выбора
    Если ВыбранныеФайлы <> Неопределено Тогда
        Для Каждого ИмяВыбранногоФайла Из ВыбранныеФайлы Цикл
            ВыбранныйФайл = Новый Файл(ИмяВыбранногоФайла);
            ПоказатьПредупреждение(, "Выбран файл: " + ВыбранныйФайл.Имя + Символы.ПС + "Размер: " + ВыбранныйФайл.Размер() + " байт");
        КонецЦикла;
    Иначе
        ПоказатьПредупреждение(, "Файл не был выбран!");
    КонецЕсли;
    
КонецПроцедуры

Этот код пишется линейно, его легко читать и отлаживать, при этом он полностью отвечает современным стандартам разработки 1С и не нарушает запрет на использование модальности.

Альтернативный вариант для более старых версий платформы 8.3

Если вы работаете на версиях платформы ниже 8.3.18, где ключевые слова Асинх и Ждать еще не поддерживаются, задачу ухода от модальности следует решать через использование описания оповещения и метода Показать().

Проанализируем этот подход на примере:


&НаКлиенте
Процедура ЗагружаемыйФайлНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    ДиалогОткрытия = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    ДиалогОткрытия.Фильтр = "Файлы Excel (*.xls; *.xlsx)|*.xls;*.xlsx";
    ДиалогОткрытия.МножественныйВыбор = Ложь;
    ДиалогОткрытия.Заголовок = "Выберите файл Excel";
    
    // Создаем описание оповещения, указывая процедуру-обработчик завершения выбора
    ОповещениеЗавершения = Новый ОписаниеОповещения("ПослеВыбораФайла", ЭтотОбъект, ДиалогОткрытия);
    
    // Открываем диалог в немодальном режиме
    ДиалогОткрытия.Показать(ОповещениеЗавершения);
    
КонецПроцедуры

&НаКлиенте
Процедура ПослеВыбораФайла(ВыбранныеФайлы, ДополнительныеПараметры) Экспорт
    
    Если ВыбранныеФайлы <> Неопределено Тогда
        Для Каждого ИмяВыбранногоФайла Из ВыбранныеФайлы Цикл
            // Выполняем логику обработки выбранного файла
        КонецЦикла;
    Иначе
        ПоказатьПредупреждение(, "Выбор отменен!");
    КонецЕсли;
    
КонецПроцедуры

Использование инструментов БСП (Библиотеки Стандартных Подсистем)

При разработке в конфигурациях, созданных на базе БСП (например, 1С:ERP, 1С:Бухгалтерия, 1С:Управление торговлей и др.), ручное создание объекта ДиалогВыбораФайла часто является избыточным и не всегда надежным решением, особенно если пользователи работают через Веб-клиент (в браузере).

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

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

Рассмотрим пример интеграции механизма БСП:


&НаКлиенте
Процедура ЗагрузитьФайлБСП(Команда)
    
    // Задаем параметры диалога через специальную структуру БСП
    ПараметрыДиалога = Новый ПараметрыДиалогаВыбораФайла;
    ПараметрыДиалога.Фильтр = "Файлы Excel (*.xls; *.xlsx)|*.xls;*.xlsx";
    ПараметрыДиалога.Заголовок = "Выберите импортируемый файл";
    ПараметрыДиалога.МножественныйВыбор = Ложь;
    
    // Описываем обработчик завершения
    Оповещение = Новый ОписаниеОповещения("ПослеВыбораФайлаБСП", ЭтотОбъект);
    
    // Вызываем стандартизированный диалог БСП
    ФайловаяСистемаКлиент.ПоказатьДиалогВыбора(Оповещение, ПараметрыДиалога);
    
КонецПроцедуры

&НаКлиенте
Процедура ПослеВыбораФайлаБСП(ВыбранныеФайлы, ДополнительныеПараметры) Экспорт
    
    Если ВыбранныеФайлы <> Неопределено Тогда
        // ВыбранныеФайлы в БСП возвращаются в виде массива путей к файлам
        Для Каждого ПутьКФайлу Из ВыбранныеФайлы Цикл
            // Реализуем чтение файла
        КонецЦикла;
    КонецЕсли;
    
КонецПроцедуры

Управление активным фильтром: свойство ИндексФильтра

В завершение рассмотрим полезный практический нюанс. Бывают ситуации, когда в одном диалоге пользователю необходимо предоставить выбор из нескольких разных типов файлов — например, отдельно таблицы Excel, отдельно текстовые документы CSV и вариант отображения «Все файлы».

Мы можем управлять тем, какой именно фильтр будет активирован по умолчанию в момент открытия окна проводника. Для этого используется свойство ИндексФильтра. Важно помнить, что индексация фильтров начинается с нуля.

Посмотрим на пример реализации:


ДиалогОткрытия.Фильтр = "Файлы Excel (*.xls; *.xlsx)|*.xls;*.xlsx|Текстовые файлы CSV (*.csv)|*.csv|Все файлы (*.*)|*.*";

// Установим по умолчанию фильтр для файлов CSV (он идет вторым по счету, индекс = 1)
ДиалогОткрытия.ИндексФильтра = 1; 

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

← На главную