При разработке обработок импорта данных из внешних источников часто возникает необходимость ограничить выбор пользователя только файлами электронных таблиц Microsoft Excel. Для решения этой задачи в платформе 1С:Предприятие используется объект ДиалогВыбораФайла. Однако неправильно заданная строка фильтра приводит к тому, что файлы в диалоговом окне отображаются некорректно или фильтрация вовсе перестает работать. В этой статье мы подробно разберем, как устроен синтаксис фильтров, исправим типичные синтаксические ошибки и рассмотрим современные стандарты разработки для управляемого приложения.
Свойство Фильтр у объекта ДиалогВыбораФайла ожидает строго структурированную текстовую строку. Если этот формат нарушен, операционная система не сможет применить ограничения к файлам в открывающейся папке. Шаблон строки фильтра выглядит следующим образом:
"ОписаниеФильтра1|МаскаФильтра1|ОписаниеФильтра2|МаскаФильтра2|..."
Символ вертикальной черты (|) выступает в роли разделителя. Он четко разграничивает текстовую информацию, которую пользователь видит на экране в выпадающем списке типов файлов (описание), и внутреннюю маску расширений, по которой операционная система фильтрует файлы на диске.
Давайте рассмотрим типичную ошибку из исходного сообщения темы:
Фильтр = НСтр("ru = 'Лист Excel'; en = 'Excel'") + "(*.xls)(*.xlsx)|*.xls|*.xlsx";
В данном коде допущено сразу несколько критических ошибок:
(*.xls)(*.xlsx) прибавлены к текстовому описанию без правильного разделения вертикальными чертами.*.xls и *.xlsx через еще одну вертикальную черту | привела к тому, что платформа восприняла *.xlsx как текстовое описание для следующего элемента фильтра, у которого в итоге отсутствовала сама маска.Если нам необходимо предоставить пользователю выбор между конкретными версиями Excel в виде отдельных пунктов списка (как предлагается в сообщении 2), мы должны разделить их вертикальной чертой следующим образом:
ДиалогОткрытияФайла.Фильтр = "Excel (*.xls)|*.xls|Excel (*.xlsx)|*.xlsx";
В этом случае в диалоговом окне появится два взаимоисключающих пункта: "Excel (*.xls)" и "Excel (*.xlsx)". Пользователю придется вручную переключаться между ними в выпадающем списке типов файлов, чтобы увидеть файлы разных форматов.
Для более удобной работы чаще всего требуется объединить несколько расширений в один общий пункт, чтобы в окне выбора одновременно отображались файлы как старого формата .xls, так и нового .xlsx. Для этого маски в правой части необходимо разделять точкой с запятой (;) без пробелов. Рассмотрим правильный пример:
ДиалогОткрытияФайла.Фильтр = "Книги Excel (*.xls; *.xlsx)|*.xls;*.xlsx";
Этот синтаксис является наиболее универсальным и предпочтительным для большинства задач по импорту табличных документов.
В ходе обсуждения участники форума предлагали использовать универсальную маску *.xl* (сообщение 4). Давайте проанализируем эту ситуацию подробнее.
Использование маски с подстановочным знаком * в конце расширения действительно позволяет сократить код и автоматически захватить такие современные форматы файлов Excel, как:
.xlsm — книги Excel с поддержкой макросов;.xlsb — двоичные книги 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
В сообщениях 5 и 6 участники обсуждения упоминали, что для разных расширений (.xls и .xlsx) обработка может работать по-разному. Раньше это было связано с использованием COM-объекта Excel.Application. Чтение через COM-объект требовало обязательного наличия установленного пакета Microsoft Office на компьютере пользователя и работало исключительно под управлением Windows.
Современный подход в 1С 8.3 полностью решает эту проблему на уровне платформы. Нам больше не нужно разделять файлы Excel по расширениям на этапе загрузки, поскольку объект ТабличныйДокумент умеет самостоятельно определять внутренний формат файла и считывать его данные без использования внешних библиотек и COM-объектов как на клиенте, так и на сервере под управлением ОС Linux.
Давайте посмотрим на пример универсального серверного чтения файлов Excel:
&НаСервере
Процедура ПрочитатьФайлExcelНаСервере(ИмяВременногоФайла)
ТабДок = Новый ТабличныйДокумент;
Попытка
ТабДок.Прочитать(ИмяВременногоФайла);
// Платформа автоматически распознает xls и xlsx
// Теперь мы можем обойти строки и колонки табличного документа
Для СтрокаНом = 1 По ТабДок.ВысотаТаблицы Цикл
ЗначениеЯчейки = ТабДок.Область(СтрокаНом, 1).Текст;
// Обработка данных ячейки...
КонецЦикла;
Исключение
ЗаписьЖурналаРегистрации("ЗагрузкаДанных", УровеньЖурналаРегистрации.Ошибка, , ,
ОписаниеОшибки());
ВызватьИсключение "Не удалось прочитать выбранный файл Excel.";
КонецПопытки;
КонецПроцедуры
Этот подход делает разработку кроссплатформенной, быстрой и независимой от стороннего программного обеспечения.