Перейти к содержанию
#std542

Доступ к файловой системе из кода конфигурации

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

1.

При работе с временными файлами и каталогами соблюдайте правила ниже.

1.1.

Для получения имени временного файла используйте ПолучитьИмяВременногоФайла() (исключение: веб-клиент, см. п. 1.3).

Иначе возможны:

  • ошибки в многопользовательском режиме;
  • проблемы с профилями безопасности и правами ОС;
  • неконтролируемый рост временных файлов.

Неправильно

ИмяПромежуточногоФайла = "C:\Временные файлы 1С\TempFile.xml";
Данные.Записать(ИмяПромежуточногоФайла);

Правильно

ИмяПромежуточногоФайла = ПолучитьИмяВременногоФайла("xml");
Данные.Записать(ИмяПромежуточногоФайла);

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

Если использовать ПолучитьИмяВременногоФайла(), платформа гарантирует уникальность имени, сохраняет контроль над файлом и удаляет его автоматически:

  • при перезапуске рабочего процесса (если файл создан на сервере) или клиентского приложения (если файл создан на клиенте);
  • через 20 минут после серверного вызова или сеанса, где создан файл (платформа 8.3.17 и выше).

Если имя временного файла сформировано другим способом и код его не удалил, файл останется в системе на неопределенное время. В больших базах это создает заметную нагрузку.

Неправильно

Каталог = КаталогВременныхФайлов();
ИмяФайла = Строка(Новый УникальныйИдентификатор) + ".xml";
ИмяПромежуточногоФайла = Каталог + ИмяФайла;
Данные.Записать(ИмяПромежуточногоФайла);

Правильно

ИмяПромежуточногоФайла = ПолучитьИмяВременногоФайла("xml");
Данные.Записать(ИмяПромежуточногоФайла);

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

1.2.

Для временного каталога также используйте имя, полученное через ПолучитьИмяВременногоФайла() (исключение: веб-клиент, см. п. 1.3).

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

1.3.

В веб-клиенте ПолучитьИмяВременногоФайла() недоступен. Используйте КаталогВременныхФайлов() и УникальныйИдентификатор.

Неправильно

Каталог = КаталогВременныхФайлов();
ИмяФайла = "TempDataFile.xml";
ИмяПромежуточногоФайла = Каталог + ИмяФайла;
Данные.Записать(ИмяПромежуточногоФайла);

Правильно

Каталог = КаталогВременныхФайлов();
ИмяФайла = Строка(Новый УникальныйИдентификатор) + ".xml";
ИмяПромежуточногоФайла = Каталог + ИмяФайла;
Данные.Записать(ИмяПромежуточногоФайла);

Если в конфигурацию встроена БСП, для создания временных каталогов на клиенте используйте ФайловаяСистемаКлиент.СоздатьВременныйКаталог().

В стандарте не указано

Чтобы веб-клиент вообще мог создавать файлы и каталоги на компьютере пользователя, нужно расширение работы с файлами. Без него код доступа к файловой системе на клиенте не заработает, а установка расширения требует действий пользователя и поддерживается не во всех браузерах.

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

1.4.

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

ИмяПромежуточногоФайла = ПолучитьИмяВременногоФайла("xml");
Данные.Записать(ИмяПромежуточногоФайла);

// Работа с файлом
...

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

Если в конфигурацию встроена БСП, используйте ФайловаяСистема.УдалитьВременныйФайл() и ФайловаяСистема.УдалитьВременныйКаталог().

См. также

#std498: Использование Журнала регистрации.

1.5.

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

В кластере следующий вызов может выполниться на другом компьютере, и файл станет недоступен. Если данные должны жить между серверными вызовами в рамках одного сеанса, используйте временное хранилище платформы (ПоместитьВоВременноеХранилище(), ПолучитьИзВременногоХранилища()).

1.6.

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

Тогда обеспечьте:

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

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

Работа с двоичными данными и потоками

2.

Обращение к файловой системе ради получения двоичных данных обычно избыточно: двоичные данные объекта в любом случае размещаются в памяти.

2.1.

Для получения двоичных данных объектов используйте потоки в памяти: ПотокВПамяти, ЗаписьДанных, ЧтениеДанных.

Неправильно

ИмяВременногоФайла = ПолучитьИмяВременногоФайла("txt");
ТекстИнформации = Новый ТекстовыйДокумент;
ТекстИнформации.УстановитьТекст(ТехнологическаяИнформация);
ТекстИнформации.Записать(ИмяВременногоФайла, КодировкаТекста.UTF8);
Результат = ПоместитьВоВременноеХранилище(Новый ДвоичныеДанные(ИмяВременногоФайла),
    Новый УникальныйИдентификатор);
УдалитьФайлы(ИмяВременногоФайла);

Правильно

ПотокФайла = Новый ПотокВПамяти;
ТекстИнформации = Новый ТекстовыйДокумент;
ТекстИнформации.УстановитьТекст(ТехнологическаяИнформация);
ТекстИнформации.Записать(ПотокФайла, КодировкаТекста.UTF8);
Результат = ПоместитьВоВременноеХранилище(ПотокФайла.ЗакрытьИПолучитьДвоичныеДанные(),
    Новый УникальныйИдентификатор);
2.2.

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

2.3.

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

Передача файлов между клиентом и сервером

3.

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

Неправильно

&НаКлиенте
Процедура ОбработатьФайл()
    ...
    ИмяФайла = "C:\Файлы для обработки\Загрузка.xml";
    Результат = ПроизвестиОбработкуНаСервере(ИмяФайла);
    ...
КонецПроцедуры

&НаСервере
Функция ПроизвестиОбработкуНаСервере(ИмяФайла)
    Чтение = Новый ЧтениеТекста(ИмяФайла);
    ...
    Результат = Чтение.Прочитать();
    Возврат Результат;
КонецФункции

Правильно

&НаКлиенте
Процедура ПродолжитьОбработкуФайла(Адрес)
    ...
    // Адрес во временном хранилище получен при помещении файла на сервер, см. п. 3.1
    Результат = ПроизвестиОбработкуНаСервере(Адрес);
    ...
КонецПроцедуры

&НаСервере
Функция ПроизвестиОбработкуНаСервере(Адрес)
    Данные = ПолучитьИзВременногоХранилища(Адрес);
    ИмяПромежуточногоФайла = ПолучитьИмяВременногоФайла("txt");
    Данные.Записать(ИмяПромежуточногоФайла);
    Чтение = Новый ЧтениеТекста(ИмяПромежуточногоФайла);
    ...
    Результат = Чтение.Прочитать();
    ...
    УдалитьФайлы(ИмяПромежуточногоФайла);
    Возврат Результат;
КонецФункции
3.1.

Для загрузки файла с клиента на сервер используйте ПоместитьФайлНаСерверАсинх(), ПоместитьФайлыНаСерверАсинх(), НачатьПомещениеФайлаНаСервер(), НачатьПомещениеФайловНаСервер().

В стандарте не указано

Эти методы появились в платформе 8.3.15 и заменяют ПоместитьФайл(), ПоместитьФайлы(), НачатьПомещениеФайла(), НачатьПомещениеФайлов().

Если данные файла должны храниться между несколькими серверными вызовами, передавайте в эти методы идентификатор текущей формы (параметр УникальныйИдентификаторФормы). Такие данные удаляются из временного хранилища только при закрытии формы. При повторном помещении того же файла предыдущее значение удаляйте вручную через УдалитьИзВременногоХранилища().

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

Если в конфигурацию встроена БСП, используйте ФайловаяСистемаКлиент.ЗагрузитьФайл() и ФайловаяСистемаКлиент.ЗагрузитьФайлы(). Чтобы сохранить данные файла между несколькими серверными вызовами, заполните свойство ИдентификаторФормы параметра ПараметрыЗагрузки. Описание помещенного файла, включая адрес во временном хранилище, придет в обработчик оповещения.

&НаКлиенте
Процедура ОбработатьФайл()
    ...
    ИмяФайлаДляОбработки = "C:\Файлы для обработки\Загрузка.xml";
    ОписаниеОповещения = Новый ОписаниеОповещения("ОбработатьФайлЗавершение", ЭтотОбъект);

    ПараметрыЗагрузки = ФайловаяСистемаКлиент.ПараметрыЗагрузкиФайла();
    ПараметрыЗагрузки.ИдентификаторФормы = УникальныйИдентификатор;
    ПараметрыЗагрузки.Интерактивно = Ложь;

    ФайловаяСистемаКлиент.ЗагрузитьФайл(ОписаниеОповещения,
        ПараметрыЗагрузки, ИмяФайлаДляОбработки);
КонецПроцедуры

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

Для сохранения (скачивания) файла сервера на клиенте используйте ПолучитьФайлССервераАсинх(), ПолучитьФайлыССервераАсинх(), НачатьПолучениеФайлаССервера(), НачатьПолучениеФайловССервера().

Если в конфигурацию встроена БСП, используйте ФайловаяСистемаКлиент.СохранитьФайл() и ФайловаяСистемаКлиент.СохранитьФайлы().

Совместимость имен файлов

4.

Даже если #std761: локализация конфигурации на другие языки не планируется, обеспечивайте переносимость автоматически сформированных файлов между ОС с разными кодировками.

4.1.

В именах файлов, которые формируются системой, используйте только английские буквы и цифры. Для текстовых файлов используйте только UTF-8.

Это особенно важно для macOS.

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

4.2.

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

По умолчанию, если это не ухудшает UX, предлагайте англоязычное имя файла и UTF-8 для текстовых файлов.

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

Если конфигурация использует БСП, для транслитерации имен файлов применяйте СтроковыеФункцииКлиентСервер.СтрокаЛатиницей().

Права доступа к файлам

5.

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

5.1.

Если код выполняется на клиенте, доступ к файловой системе идет под правами пользователя, который запустил приложение (тонкий, толстый или веб-клиент). Обычно это текущий пользователь ОС.

5.2.

Если код выполняется на сервере:

  • в клиент-серверном варианте доступ ограничен правами пользователя, от имени которого запущен сервер 1С:Предприятия;
  • в файловом варианте, опубликованном на веб-сервере, доступ ограничен правами пользователя веб-сервера.

Рабочие процессы могут быть запущены от имени пользователя, отличного от пользователя агента сервера. Подробно: описание служебного файла swpuser.ini.

Безопасность файловой системы

6.

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

6.1.

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

Служебные реквизиты объекта пользователь напрямую изменить не может, но они попадают в данные формы (в основной реквизит Объект). Для них при записи на сервере проверяйте, что значение не изменили на клиенте.

6.2.

Запрещено передавать путь к файлу в параметры серверных процедур форм и экспортных процедур серверных общих модулей. Такие процедуры можно вызвать с клиента сторонними средствами.

6.3.

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

  • опишите на сервере коллекцию допустимых расширений и проверяйте вхождение переданного значения в нее;
  • используйте ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыВИмениФайла() из БСП.
6.4.

Если путь к файлу формируется по данным из информационной базы (например, по полю ввода, которое редактирует пользователь), используйте ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыВИмениФайла() из БСП.

6.5.

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

Пример 1

// Проверка, что Путь получен методом ПолучитьИмяВременногоФайла()
Файл = Новый Файл(Путь);
Возврат СтрНачинаетсяС(Файл.ПолноеИмя, КаталогВременныхФайлов());

Пример 2

// Проверка, что Путь получен из константы файлового хранилища
КаталогХранилищаФайлов = Константы.КаталогХранилищаФайловНаСервере.Получить();
Файл = Новый Файл(Путь);
Возврат СтрНачинаетсяС(Файл.ПолноеИмя, КаталогХранилищаФайлов);
6.6.

При работе с временными файлами убедитесь, что выполняются условия:

  • вся работа с файлом идет в рамках одной процедуры;
  • путь к файлу получен методом ПолучитьИмяВременногоФайла() и не изменяется;
  • после использования файл на диске удаляется.
6.7.

Запрещено записывать файлы в каталог исполняемых файлов платформы, получаемый через КаталогПрограммы().

КаталогПрограммы() допустимо использовать только для чтения или запуска файлов.

Сам запуск выполняйте по правилам #std774: Безопасность запуска приложений.

6.8.

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

См. также
Источники