Как правильно настроить фильтр диалога выбора файлов Excel в 1С?

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

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

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

Свойство Фильтр у объекта ДиалогВыбораФайла ожидает строго структурированную текстовую строку. Если этот формат нарушен, операционная система не сможет применить ограничения к файлам в открывающейся папке. Шаблон строки фильтра выглядит следующим образом:

"ОписаниеФильтра1|МаскаФильтра1|ОписаниеФильтра2|МаскаФильтра2|..."

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

Давайте рассмотрим типичную ошибку из исходного сообщения темы:


Фильтр = НСтр("ru = 'Лист Excel'; en = 'Excel'") + "(*.xls)(*.xlsx)|*.xls|*.xlsx";

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

  1. Символы маски файлов (*.xls)(*.xlsx) прибавлены к текстовому описанию без правильного разделения вертикальными чертами.
  2. Попытка разделить маски *.xls и *.xlsx через еще одну вертикальную черту | привела к тому, что платформа восприняла *.xlsx как текстовое описание для следующего элемента фильтра, у которого в итоге отсутствовала сама маска.

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

Если нам необходимо предоставить пользователю выбор между конкретными версиями Excel в виде отдельных пунктов списка (как предлагается в сообщении 2), мы должны разделить их вертикальной чертой следующим образом:

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

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

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

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

Этот синтаксис является наиболее универсальным и предпочтительным для большинства задач по импорту табличных документов.

Учитываем современные форматы Excel и маски

В ходе обсуждения участники форума предлагали использовать универсальную маску *.xl* (сообщение 4). Давайте проанализируем эту ситуацию подробнее.

Использование маски с подстановочным знаком * в конце расширения действительно позволяет сократить код и автоматически захватить такие современные форматы файлов Excel, как:

Однако у маски *.xl* есть скрытая опасность. В диалоговое окно могут попасть временные файлы или файлы резервных копий Excel (например, с расширением .xlk). Чтобы избежать случайного выбора некорректных файлов пользователем, надежнее явно перечислить все необходимые расширения через точку с запятой:


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

Как правильно локализовать фильтр с помощью НСтр()

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

При использовании функции НСтр() необходимо локализовать всю конструкцию фильтра целиком, включая маски и разделители. Рассмотрим правильный пример локализации:


Фильтр = НСтр("ru = 'Книги Excel (*.xls; *.xlsx)|*.xls;*.xlsx'; en = 'Excel files (*.xls; *.xlsx)|*.xls;*.xlsx'");
ДиалогОткрытияФайла.Фильтр = Фильтр;

Это гарантирует, что структура строки фильтра останется целостной при переключении языков интерфейса платформы.

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

Код, представленный в исходном вопросе, написан в синхронном стиле (для обычного приложения 1С). В современных конфигурациях на управляемых формах (1С v8.3) использование синхронных вызовов (таких как метод Выбрать()) запрещено конфигурацией или настройками платформы из-за требований кроссплатформенности и стабильной работы в веб-клиенте.

Давайте разберем по шагам, как переписать этот алгоритм под асинхронный стандарт с использованием объекта ОписаниеОповещения.


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

&НаКлиенте
Процедура ПослеВыбораФайла(ВыбранныеФайлы, ДополнительныеПараметры) Экспорт
    
    Если ВыбранныеФайлы = Неопределено Тогда
        Возврат; // Пользователь закрыл диалог или нажал Отмена
    КонецЕсли;
    
    ПутьКФайлу = ВыбранныеФайлы[0];
    // Далее вызываем процедуру обработки файла
    ОбработатьВыбранныйФайл(ПутьКФайлу);
    
КонецПроцедуры

Такой код будет корректно работать на любых клиентах, включая тонкий клиент под Windows/Linux и веб-клиент в любом веб-браузере.

Решение через Библиотеку стандартных подсистем (БСП)

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

Рассмотрим, как реализовать выбор файла с помощью общего модуля БСП ФайловаяСистемаКлиент:


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

&НаКлиенте
Процедура ПослеВыбораФайлаБСП(ВыбранныеФайлы, ДополнительныеПараметры) Экспорт
    
    Если ВыбранныеФайлы <> Неопределено И ВыбранныеФайлы.Количество() > 0 Тогда
        ПутьКФайлу = ВыбранныеФайлы[0];
        // Выполняем импорт данных
    КонецЕсли;
    
EndProcedure

Современный кроссплатформенный подход к обработке Excel

В сообщениях 5 и 6 участники обсуждения упоминали, что для разных расширений (.xls и .xlsx) обработка может работать по-разному. Раньше это было связано с использованием COM-объекта Excel.Application. Чтение через COM-объект требовало обязательного наличия установленного пакета Microsoft Office на компьютере пользователя и работало исключительно под управлением Windows.

Современный подход в 1С 8.3 полностью решает эту проблему на уровне платформы. Нам больше не нужно разделять файлы Excel по расширениям на этапе загрузки, поскольку объект ТабличныйДокумент умеет самостоятельно определять внутренний формат файла и считывать его данные без использования внешних библиотек и COM-объектов как на клиенте, так и на сервере под управлением ОС Linux.

Давайте посмотрим на пример универсального серверного чтения файлов Excel:


&НаСервере
Процедура ПрочитатьФайлExcelНаСервере(ИмяВременногоФайла)
    
    ТабДок = Новый ТабличныйДокумент;
    Попытка
        ТабДок.Прочитать(ИмяВременногоФайла);
        // Платформа автоматически распознает xls и xlsx
        // Теперь мы можем обойти строки и колонки табличного документа
        Для СтрокаНом = 1 По ТабДок.ВысотаТаблицы Цикл
            ЗначениеЯчейки = ТабДок.Область(СтрокаНом, 1).Текст;
            // Обработка данных ячейки...
        КонецЦикла;
    Исключение
        ЗаписьЖурналаРегистрации("ЗагрузкаДанных", УровеньЖурналаРегистрации.Ошибка, , , 
            ОписаниеОшибки());
        ВызватьИсключение "Не удалось прочитать выбранный файл Excel.";
    КонецПопытки;
    
КонецПроцедуры

Этот подход делает разработку кроссплатформенной, быстрой и независимой от стороннего программного обеспечения.

← На главную