Запись файла на диск из кода 1С:Предприятия 8.3

· 9 мин

Содержание

Создать файл на диске в 1С проще всего тремя строками: Текст = Новый ТекстовыйДокумент, Текст.ДобавитьСтроку("..."), Текст.Записать("C:\Обмен\out.txt", КодировкаТекста.UTF8). Для двоичных данных хватит одной строки ДД.Записать(ИмяФайла). Отдельной функции «создать файл» в платформе нет: файл появляется в момент записи.

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

Какой объект выбрать для записи файла

Сначала определитесь с типом содержимого. Дальше выбор почти однозначный.

Что пишемОбъектКогда удобен
Небольшой текст целикомТекстовыйДокументОтчёт, CSV до нескольких мегабайт, файл настроек
Текст построчно, логЗаписьТекстаБольшие выгрузки, дописывание в конец файла
Готовый файл, картинка, PDFДвоичныеДанныеСохранить вложение, данные из хранилища или Base64
Байты по одному, свой форматЗаписьДанныхБинарные протоколы, заголовки файлов
Большие объёмы без загрузки в памятьФайловыйПоток / ФайловыеПотокиКопирование и склейка файлов в сотни мегабайт
XML, JSONЗаписьXML, ЗаписьJSONСтруктурированный обмен

ЗаписьДанных, потоки и ФайловыеПотоки появились в платформе 8.3.9. На всех актуальных релизах 8.3.2x они доступны.

Путь к файлу и объект Файл: проверки перед записью

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

Что умеет объект Файл

Объект создаётся конструктором Новый Файл(ПолноеИмя). Самые полезные свойства и методы:

  • 📄 Имя, ИмяБезРасширения, Расширение — части имени файла;
  • 📁 Путь — каталог с завершающим разделителем, ПолноеИмя — весь путь;
  • ✅ Существует() — есть ли файл или каталог на диске;
  • 📂 ЭтоКаталог(), ЭтоФайл() — что именно лежит по пути;
  • 📏 Размер() — размер в байтах;
  • 🕒 ПолучитьВремяИзменения() — дата последнего изменения.

Создать каталог, если его нет

ТекстовыйДокумент.Записать и ЗаписьТекста не создают недостающие папки. Если каталога C:\Обмен\2026 нет, запись упадёт с исключением. Поэтому каталог проверяют заранее:

Функция ПодготовитьКаталог(Каталог)
	ФайлКаталога = Новый Файл(Каталог);
	Если Не ФайлКаталога.Существует() Тогда
		СоздатьКаталог(Каталог);
	ИначеЕсли Не ФайлКаталога.ЭтоКаталог() Тогда
		ВызватьИсключение "По пути " + Каталог + " лежит файл, а не каталог";
	КонецЕсли;
	Возврат Каталог;
КонецФункции

СоздатьКаталог создаёт и промежуточные уровни, если их нет.

Собрать путь без ошибок

Разделитель в Windows — \, в Linux — /. Если код может выполниться на сервере под Linux, не зашивайте обратный слеш, а берите его функцией ПолучитьРазделительПути():

Разделитель = ПолучитьРазделительПути();
ИмяФайла = Каталог + Разделитель + "export_" + Формат(ТекущаяДатаСеанса(), "ДФ=yyyyMMdd_HHmmss") + ".csv";

Дата в имени снимает проблему перезаписи. Символы \ / : * ? " < > | в имени файла Windows недопустимы, поэтому наименования номенклатуры или контрагентов в имя подставляйте только после замены этих символов через СтрЗаменить.

В Linux имена файлов чувствительны к регистру: Export.csv и export.csv — два разных файла.

Как записать текстовый файл на диск

Два основных инструмента — ТекстовыйДокумент и ЗаписьТекста. Первый держит весь текст в памяти и пишет его разом. Второй пишет строку за строкой.

ТекстовыйДокумент: весь текст за один вызов

Процедура СоздатьТекстовыйФайл(ПолноеИмяФайла)
	Текст = Новый ТекстовыйДокумент;
	Текст.ДобавитьСтроку("Выгрузка от " + Формат(ТекущаяДатаСеанса(), "ДФ=dd.MM.yyyy"));
	Текст.ДобавитьСтроку("Строк в отчете: " + Формат(125, "ЧГ=0"));
	Текст.Записать(ПолноеИмяФайла, КодировкаТекста.UTF8);
КонецПроцедуры

Если файл уже есть, Записать перезапишет его целиком. Второй параметр — кодировка. Без него платформа выберет кодировку по умолчанию, и файл может открыться «кракозябрами» в другой программе.

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

ЗаписьТекста: построчно и с дописыванием

Конструктор Новый ЗаписьТекста(ИмяФайла, Кодировка, РазделительСтрок, Дописывание). Четвёртый параметр Истина включает дописывание в конец файла, а если файла нет — он будет создан.

Пример простого журнала обмена:

Процедура ЗаписатьВЛог(ИмяЛога, Сообщение)
	Запись = Новый ЗаписьТекста(ИмяЛога, КодировкаТекста.UTF8, , Истина);
	Попытка
		Запись.ЗаписатьСтроку(Формат(ТекущаяДатаСеанса(), "ДФ='dd.MM.yyyy HH:mm:ss'") + " | " + Сообщение);
		Запись.Закрыть();
	Исключение
		Запись.Закрыть();
		ВызватьИсключение;
	КонецПопытки;
КонецПроцедуры

Методы записи: ЗаписатьСтроку добавляет перевод строки, Записать — нет. Всегда вызывайте Закрыть() — до этого часть данных может оставаться в буфере, а файл будет занят процессом 1С.

Кодировка и BOM

ЗначениеЧто получитсяКому подходит
КодировкаТекста.UTF8UTF-8 с меткой BOMExcel, Блокнот, большинство программ Windows
КодировкаТекста.ANSIWindows-1251Старые программы, банковские форматы 1С-обмена
КодировкаТекста.OEMКодировка консоли (866)bat-файлы с русским текстом
КодировкаТекста.UTF16UTF-16Редкие интеграции

Метка BOM — три служебных байта в начале файла. Часть внешних сервисов и скриптов её не ждёт, и первая строка у них ломается. Надёжный способ записать UTF-8 без BOM — получить двоичные данные из строки с явным отказом от метки:

ДД = ПолучитьДвоичныеДанныеИзСтроки(ТекстФайла, КодировкаТекста.UTF8, Ложь);
ДД.Записать(ИмяФайла);

Третий параметр функции отвечает за вывод BOM.

Двоичные данные и потоки: картинки, PDF, большие файлы

ДвоичныеДанные: сохранить готовое содержимое

Объект ДвоичныеДанные хранит содержимое файла целиком и пишет его одной командой:

// Из реквизита типа ХранилищеЗначения
ДД = Объект.Скан.Получить();
ДД.Записать("C:\Архив\scan.pdf");

// Из строки Base64, пришедшей от веб-сервиса
ДД = Base64Значение(СтрокаBase64);
ДД.Записать("C:\Обмен\invoice.pdf");

Обратная операция — Новый ДвоичныеДанные(ИмяФайла) читает файл в память. Для файлов в десятки мегабайт это нормально. Для сотен мегабайт лучше потоки.

ЗаписьДанных: свой бинарный формат

Когда нужно записать байты, числа и строки в заданном порядке, используйте ЗаписьДанных:

Запись = Новый ЗаписьДанных(ИмяФайла);
Запись.ЗаписатьСтроку("HDR");
Запись.ЗаписатьБайт(1);
Запись.ЗаписатьЦелое32(КоличествоЗаписей);
Запись.Закрыть();

Потоки: копирование без загрузки в память

ФайловыеПотоки — менеджер, который открывает файл как поток. Копирование большого файла выглядит так:

Источник = ФайловыеПотоки.ОткрытьДляЧтения(ИсходныйФайл);
Приемник = ФайловыеПотоки.ОткрытьДляЗаписи(НовыйФайл);
Источник.КопироватьВ(Приемник);
Приемник.Закрыть();
Источник.Закрыть();

Если нужно управлять режимом открытия, создайте поток конструктором: Новый ФайловыйПоток(ИмяФайла, РежимОткрытияФайла.Создать). Значение СоздатьНовый выдаст ошибку, если файл уже существует, — удобно, когда перезапись недопустима. Дописать открывает файл для записи в конец.

Где появится файл в клиент-серверной базе

Самый частый вопрос от тех, кто перешёл с файловой базы на серверную: «код отработал без ошибок, а файла нет». Файл есть — но на другом компьютере.

Клиент и сервер пишут на разные диски

  • 🖥️ Код в процедуре &НаКлиенте пишет на диск компьютера пользователя (в тонком клиенте).
  • 🗄️ Код &НаСервере, в общих модулях с флагом «Сервер», в регламентных заданиях пишет на диск сервера 1С.
  • 👤 На сервере файл создаётся от имени пользователя, под которым запущена служба агента сервера (часто это USR1CV8), а не от имени того, кто нажал кнопку.

Отсюда три практических следствия. Папке на сервере нужно выдать права на запись этой учётной записи. Подключённые сетевые диски вроде Z: служба не видит — используйте UNC-путь \\fileserver\obmen\. А у служебной учётной записи должен быть доступ к этой сетевой папке.

Как отдать файл, созданный на сервере, пользователю

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

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

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

ФайловаяСистемаКлиент — модуль Библиотеки стандартных подсистем, он есть в БП 3.0, ЗУП 3.1, УТ 11 и других типовых. В своей конфигурации без БСП используйте асинхронную функцию платформы ПолучитьФайлССервераАсинх (платформа не ниже 8.3.18) или старый ПолучитьФайл — но он открывает модальный диалог и не работает при отключённой модальности.

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

Веб-клиент

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

Обработка ошибок при создании файла

Запись файла — внешняя операция. Диск может быть заполнен, файл открыт в Excel, у службы может не быть прав. Поэтому любой код записи оборачивают в Попытка … Исключение.

Функция ЗаписатьФайлБезопасно(ИмяФайла, ТекстФайла)
	Попытка
		Текст = Новый ТекстовыйДокумент;
		Текст.УстановитьТекст(ТекстФайла);
		Текст.Записать(ИмяФайла, КодировкаТекста.UTF8);
		Возврат Истина;
	Исключение
		ЗаписьЖурналаРегистрации("Выгрузка файла", УровеньЖурналаРегистрации.Ошибка, , ,
			"Файл " + ИмяФайла + ": " + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		Возврат Ложь;
	КонецПопытки;
КонецФункции

В журнал регистрации пишите подробное представление: в нём видна строка модуля и исходный текст системной ошибки. Пользователю достаточно ОписаниеОшибки().

Диагностика: выберите симптом

Шпаргалка по функциям для работы с файловой системой

Функции глобального контекста, которые нужны вместе с записью файлов:

ФункцияЧто делает
СоздатьКаталог(Путь)Создаёт каталог со всеми промежуточными уровнями
КопироватьФайл(Откуда, Куда)Копирует файл, существующий перезаписывает
ПереместитьФайл(Откуда, Куда)Перемещает или переименовывает файл
УдалитьФайлы(Путь, Маска)Удаляет файл или файлы по маске в каталоге
НайтиФайлы(Путь, Маска, ВПодкаталогах)Возвращает массив объектов Файл
ПолучитьИмяВременногоФайла("txt")Уникальное имя во временном каталоге
КаталогВременныхФайлов()Путь к временному каталогу текущего процесса
ПолучитьРазделительПути()\ или / в зависимости от ОС

Пример: удалить файлы выгрузки, которые старше 30 дней.

Граница = ТекущаяДатаСеанса() - 30 * 86400;
Для Каждого НайденныйФайл Из НайтиФайлы("C:\Обмен", "export_*.csv") Цикл
	Если НайденныйФайл.ПолучитьВремяИзменения() < Граница Тогда
		УдалитьФайлы(НайденныйФайл.ПолноеИмя);
	КонецЕсли;
КонецЦикла;

30 дней × 86 400 секунд = 2 592 000 секунд — именно это вычитается из текущей даты.

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

Частые вопросы

Можно ли создать пустой файл?
Да. Запишите пустой ТекстовыйДокумент или откройте поток ФайловыеПотоки.ОткрытьДляЗаписи(ИмяФайла) и сразу закройте его. Поток без записи даёт файл размером 0 байт.
Как записать файл в регламентном задании?
Регламентное задание выполняется на сервере, поэтому путь должен быть доступен серверу 1С, а права на запись — у учётной записи службы. Клиентские методы там недоступны.
Чем ЗаписьТекста лучше ТекстовогоДокумента?
Она не держит весь текст в памяти и умеет дописывать в конец файла. Для выгрузки сотен тысяч строк и для логов это заметно экономнее.
Как сохранить табличный документ в файл?
У ТабличныйДокумент есть свой метод Записать(ИмяФайла, ТипФайлаТабличногоДокумента.XLSX). Аналогично поддерживаются PDF, MXL и другие форматы из того же перечисления.
Можно ли записать файл в файловой базе так же, как в серверной?
Да, код тот же. Разница только в том, что в файловой базе серверный код выполняется на компьютере пользователя, поэтому «потерянных» файлов не бывает. После перевода базы на сервер такой код начинает писать на диск сервера.