Запись файла на диск из кода 1С:Предприятия 8.3
Содержание
Создать файл на диске в 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
| Значение | Что получится | Кому подходит |
|---|---|---|
КодировкаТекста.UTF8 | UTF-8 с меткой BOM | Excel, Блокнот, большинство программ Windows |
КодировкаТекста.ANSI | Windows-1251 | Старые программы, банковские форматы 1С-обмена |
КодировкаТекста.OEM | Кодировка консоли (866) | bat-файлы с русским текстом |
КодировкаТекста.UTF16 | UTF-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 байт.Как записать файл в регламентном задании?
Чем ЗаписьТекста лучше ТекстовогоДокумента?
Как сохранить табличный документ в файл?
ТабличныйДокумент есть свой метод Записать(ИмяФайла, ТипФайлаТабличногоДокумента.XLSX). Аналогично поддерживаются PDF, MXL и другие форматы из того же перечисления.