Как программно открыть файл MXL на клиенте с сохранением связи с файлом?

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

В процессе разработки на платформе 1С:Предприятие 8.3 часто возникает задача программно открыть файл табличного документа (.mxl) так, чтобы это выглядело для пользователя максимально естественно. Под «естественностью» мы понимаем не просто отображение данных, но и сохранение связи с исходным файлом на диске. Если пользователь нажмет кнопку «Сохранить» или комбинацию клавиш Ctrl+S, система должна обновить существующий файл, а не предлагать выбрать путь заново. Рассмотрим, как реализовать этот функционал, обходя ограничения клиент-серверной архитектуры.

Проблема разрыва связи между объектом и файлом

Когда мы работаем в тонком клиенте, у нас нет возможности напрямую вызвать метод Прочитать() объекта ТабличныйДокумент, указав путь к файлу на локальном компьютере. Платформа требует, чтобы чтение данных происходило на стороне сервера. Однако простая передача файла на сервер, его чтение в объект и возврат этого объекта на клиент приводят к потере метаданных о пути к файлу. В итоге мы получаем «безымянный» документ.

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

Метод 1: Использование асинхронного помещения файла и метода Показать()

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

Проанализируем следующий пример кода:


&НаКлиенте
Процедура ОткрытьФайл(Команда)
    // Настраиваем параметры диалога выбора файла
    ПараметрыДиалога = Новый ПараметрыДиалогаПомещенияФайлов("Открытие файла", Ложь, "Табличный документ(*.mxl)|*.mxl");
    
    // Создаем описание оповещения для обработки результата
    ОписаниеЗавершение = Новый ОписаниеОповещения("ЗавершениеПомещенияФайла", ЭтаФорма);
    
    // Помещаем файл во временное хранилище
    НачатьПомещениеФайлаНаСервер(ОписаниеЗавершение, , , , ПараметрыДиалога, УникальныйИдентификатор);
КонецПроцедуры

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

    Адрес = ОписаниеПомещенногоФайла.Адрес;
    ПутьКФайлу = ОписаниеПомещенногоФайла.СсылкаНаФайл.Файл.ПолноеИмя;
    
    // Создаем новый объект и читаем данные на сервере
    ТабДок = Новый ТабличныйДокумент;
    ПрочитатьТабДокНаСервере(ТабДок, Адрес);
    
    // Ключевой момент: устанавливаем связь с файлом через метод Показать
    // Второй параметр метода - это путь к файлу, который "привязывает" документ к диску
    ТабДок.Показать(ПутьКФайлу, ПутьКФайлу);
КонецПроцедуры

&НаСервере
Процедура ПрочитатьТабДокНаСервере(ТабДок, Адрес)
    // Получаем данные из хранилища и открываем поток для чтения
    Данные = ПолучитьИзВременногоХранилища(Адрес);
    Поток = Данные.ОткрытьПотокДляЧтения();
    ТабДок.Прочитать(Поток);
    Поток.Закрыть();
КонецПроцедуры

В данном примере мы используем метод Показать(). Обратите внимание на его параметры: Показать(Заголовок, ИмяФайла). Передавая во второй параметр полный путь к исходному файлу ПутьКФайлу, мы сообщаем платформе, что этот документ открыт именно из этого места. Теперь стандартные команды сохранения будут работать корректно.

Метод 2: Использование свойства ИспользуемоеИмяФайла

Существует и другой подход, который полезен, если вы выводите табличный документ не в отдельное окно через Показать(), а отображаете его непосредственно в поле формы. У объекта ТабличныйДокумент есть программное свойство ИспользуемоеИмяФайла.

Рассмотрим, как это работает. После того как мы прочитали документ на сервере и вернули его на клиент, нам необходимо выполнить следующее действие:


&НаКлиенте
Процедура ПослеЗагрузкиНаКлиенте(ПолученныйТабДок, ИсходныйПуть)
    // Присваиваем объекту путь к файлу
    ПолученныйТабДок.ИспользуемоеИмяФайла = ИсходныйПуть;
    
    // Теперь, если этот ТабДок отображен на форме в поле табличного документа,
    // система будет знать, куда его сохранять по умолчанию.
    ЭтаФорма.Элементы.ПолеТабличногоДокумента.Отобразить(ПолученныйТабДок);
КонецПроцедуры

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

Оптимизация чтения: Потоки против временных файлов

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

Посмотрим на более эффективный вариант реализации серверной части:


&НаСервере
Функция ПрочитатьMXL_в_ТабДок(Адрес)
    ТабДок = Новый ТабличныйДокумент;
    ДвоичныеДанныеФайла = ПолучитьИзВременногоХранилища(Адрес);
    
    // Чтение напрямую из потока в памяти
    Поток = ДвоичныеДанныеФайла.ОткрытьПотокДляЧтения();
    Попытка
        ТабДок.Прочитать(Поток, СпособЧтенияЗначенийТабличногоДокумента.Значение);
    Исключение
        Сообщить("Ошибка чтения файла: " + ОписаниеОшибки());
    КонецПопытки;
    Поток.Закрыть();
    
    Возврат ТабДок;
КонецФункции

В методе Прочитать() мы указали параметр СпособЧтенияЗначенийТабличногоДокумента.Значение. Это позволяет сохранить типизацию данных в ячейках (даты как даты, числа как числа), что критически важно, если файл .mxl в дальнейшем будет использоваться для расчетов или обработки данных, а не просто для визуального просмотра.

Особенности работы в Веб-клиенте

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

В веб-клиенте алгоритм всегда будет следующим:

  1. Загрузка файла на сервер через диалог.
  2. Отображение в интерфейсе.
  3. При попытке сохранения пользователю будет предложено скачать новую версию файла через стандартный механизм загрузок браузера.

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

Имитация системной команды «Открыть»

Иногда разработчики пытаются вызвать стандартную команду Файл - Открыть программно. Однако платформа не предоставляет прямого метода для вызова этого диалога с возвратом управления в код. Поэтому описанная выше связка: ДиалогВыбораФайла -> Помещение во временное хранилище -> Прочитать() на сервере -> Показать() на клиенте — является единственным надежным способом имитации системного поведения.

Подведем итог. Чтобы успешно открыть mxl файл на клиенте и не потерять связь с диском, мы должны:

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

← На главную