Как получить и сохранить время изменения клиентского файла при передаче на сервер в 1С?

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

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

Попытка прочитать дату модификации на клиенте классическим синхронным методом ПолучитьВремяИзменения() в современных конфигурациях вызывает исключение: «Режим использования синхронных методов отключён». Разберем по шагам, почему возникает эта ошибка, как правильно прочитать время изменения на клиенте и как восстановить или сохранить его на стороне сервера.

Выясним причину ошибки на клиенте

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

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

Способ 1. Получение времени изменения через асинхронные методы (с описанием оповещения)

Рассмотрим традиционный асинхронный подход, доступный в управляемом приложении. Для получения времени последнего изменения исходного файла на клиенте используется метод НачатьПолучениеВремениИзменения() или метод для работы в шкале UTC — НачатьПолучениеУниверсальногоВремениИзменения().

Разберем реализацию этого сценария:

  1. На клиенте создаем объект Файл с путем к исходному файлу.
  2. Формируем объект ОписаниеОповещения, указывающий на процедуру обратного вызова.
  3. Вызываем асинхронное получение даты.
  4. В процедуре обработки оповещения отправляем файл во временное хранилище и передаем полученную дату отдельным параметром в серверную процедуру.

Посмотрим на пример кода на клиенте:


&НаКлиенте
Процедура ПроверитьИОтправитьФайл(ПутьКФайлу)
    ФайлНаКлиенте = Новый Файл(ПутьКФайлу);
    Оповещение = Новый ОписаниеОповещения("ПослеПолученияВремени", ЭтотОбъект, ПутьКФайлу);
    
    // Получаем универсальное время изменения (UTC), чтобы избежать расхождений часовых поясов
    ФайлНаКлиенте.НачатьПолучениеУниверсальногоВремениИзменения(Оповещение);
КонецПроцедуры

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

Способ 2. Использование современных асинхронных функций и оператора «Ждать»

Если конфигурация разрабатывается для современных версий платформы 1С:Предприятие 8.3 с поддержкой асинхронных функций, код можно существенно упростить без создания лишних процедур оповещения. Используем оператор Ждать и метод НайтиФайлыАсинх().

Посмотрим на пример реализации в асинхронной процедуре:


&НаКлиенте
Асинх Процедура ЗагрузитьФайлСКлиента(ПолныйПутьКФайлу)
    // Асинхронно находим файл, чтобы безопасно прочитать его свойства
    НайденныеФайлы = Ждать НайтиФайлыАсинх(ПолныйПутьКФайлу);
    Если НайденныеФайлы.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;
    
    ФайлКлиента = НайденныеФайлы[0];
    ВремяИзмененияUTC = Ждать ФайлКлиента.ПолучитьУниверсальноеВремяИзмененияАсинх();
    
    // Помещаем файл во временное хранилище асинхронным методом
    РезультатПомещения = Ждать ПоместитьФайлВХранилищеАсинх(ПолныйПутьКФайлу, , УникальныйИдентификатор);
    Если РезультатПомещения <> Неопределено И РезультатПомещения.Помещен Тогда
        ОбработатьФайлНаСервере(РезультатПомещения.Адрес, ВремяИзмененияUTC);
    КонецЕсли;
КонецПроцедуры

Работа с полученным временем на стороне сервера

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

Вариант А: Физическая установка даты файла на диске сервера

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

Разберем код серверной процедуры:


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

Вариант Б: Сохранение метаданных в базе данных

В типовых конфигурациях считается хорошей практикой не зависеть от файловых атрибутов операционной системы сервера. Если файл регистрируется в системе (например, в справочнике присоединенных файлов или регистре сведений), переданное значение ВремяИзмененияUTC просто сохраняется в реквизит с типом Дата. Это исключает любые искажения, связанные с кэшированием или особенностями файловых систем серверов под управлением Linux и Windows.

Важные нюансы при работе со временем в клиент-серверной архитектуре

  1. Разница в часовых поясах: Всегда отдавайте предпочтение универсальному времени (UTC) через методы НачатьПолучениеУниверсальногоВремениИзменения() / УстановитьУниверсальноеВремяИзменения(). Использование локального времени приведет к сдвигам дат, если сервер и рабочее место клиента находятся в разных регионах.
  2. Особенности веб-клиента: В браузере прямой доступ к путям локальной файловой системы ограничен из соображений безопасности. Для выполнения подобных операций на стороне веб-клиента обязательно должно быть заранее подключено расширение работы с файлами с помощью метода ПодключитьРасширениеРаботыСФайлами().
← На главную