Запись в текстовый файл из кода 1С:Предприятия 8.3
Содержание
Записать текстовый файл в 1С проще всего объектом ЗаписьТекста: создаёте его с именем файла и кодировкой, вызываете ЗаписатьСтроку() нужное число раз и обязательно Закрыть(). Три строки кода, и файл на диске. Тема общая для платформы 8.3, от конфигурации не зависит: в БП, ЗУП, УТ и в своей обработке всё работает одинаково.
Частое заблуждение — что файл появится на компьютере пользователя, где бы ни выполнялся код. Нет. Если запись идёт в серверной процедуре, файл ляжет на диск сервера 1С. А в веб-клиенте прямой записи на локальный диск нет вообще: файл готовят на сервере и передают браузеру. Поэтому сначала решите, где выполняется код, и только потом выбирайте путь к файлу.
Чем писать текст в файл: три объекта платформы
У платформы есть три штатных способа записать текст. Они не взаимозаменяемы, у каждого своя ниша.
| Объект | Как работает | Когда брать |
|---|---|---|
ЗаписьТекста | Пишет строку за строкой прямо в файл, в памяти ничего не копит | Логи, большие выгрузки, CSV на сотни тысяч строк |
ТекстовыйДокумент | Собирает весь текст в памяти, потом сохраняет одним вызовом | Небольшой текст, который нужно ещё и показать пользователю или отредактировать |
ДвоичныеДанные | Строка превращается в байты и записывается целиком | Нужен точный контроль над байтами: UTF-8 без BOM, передача файла клиенту |
Для служебных задач есть ещё ЗаписьДанных — потоковая запись байтов и строк в поток или файл. Она нужна реже, когда формат смешанный: часть текстом, часть двоичными блоками.
Простое правило: пишете много и построчно — ЗаписьТекста. Нужно показать результат на экране — ТекстовыйДокумент. Нужен файл «байт в байт» под чужую систему — ДвоичныеДанные.
Кодировка и режим записи: что указать в параметрах
Конструктор ЗаписьТекста принимает до пяти параметров:
Запись = Новый ЗаписьТекста(ИмяФайла, Кодировка, РазделительСтрок, Дописывание, РазделительСтрокВФайле);
ИмяФайла— полный путь, напримерC:\Exchange\out.txt.Кодировка— значение системного перечисленияКодировкаТекстаили строка с именем кодировки.РазделительСтрок— какой символ в строках 1С считать концом строки. Обычно не указывают.Дописывание—Истина, чтобы добавлять в конец существующего файла;Ложь(по умолчанию) — перезаписать.РазделительСтрокВФайле— чем разделять строки в самом файле. По умолчанию это пара символов ВК+ПС, как принято в Windows.
Какую кодировку выбрать
| Значение | Что получится | Для чего |
|---|---|---|
КодировкаТекста.UTF8 | UTF-8 с BOM (три служебных байта в начале) | Современные системы, кириллица без потерь |
КодировкаТекста.ANSI | Windows-1251 на русской Windows | Старые программы, Excel при открытии CSV двойным щелчком |
КодировкаТекста.OEM | Кодовая страница 866 | Файлы для консоли и bat-скриптов |
КодировкаТекста.UTF16 | UTF-16 | Редко, по требованию принимающей стороны |
КодировкаТекста.Системная | Кодировка операционной системы сервера или клиента | Когда файл читает программа на той же машине |
Если кодировку не указать, платформа запишет файл в UTF-8. Для обмена с внешними системами это не всегда то, что нужно: многие старые программы ждут Windows-1251, а некоторые парсеры спотыкаются о BOM.
КодировкаТекста.ANSI зависит от настроек ОС. На Linux-сервере 1С «ANSI» — это не обязательно Windows-1251. Если файл уходит во внешнюю систему, надёжнее указать кодировку явно строкой: "windows-1251".
Пошаговая запись текстового файла через ЗаписьТекста
Минимальный рабочий порядок:
- Определите, где выполняется код: на клиенте или на сервере. От этого зависит, на чей диск ляжет файл.
- Сформируйте путь. Для временных файлов используйте
ПолучитьИмяВременногоФайла("txt")— платформа сама подберёт каталог и уникальное имя. - Создайте объект
ЗаписьТекстас нужной кодировкой. - Пишите данные:
ЗаписатьСтроку()добавляет текст и перевод строки,Записать()— только текст. - Вызовите
Закрыть(). До этого файл может быть заблокирован, а часть данных не сброшена на диск.
ИмяФайла = "C:\Exchange\report.txt";
Запись = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.UTF8);
Запись.ЗаписатьСтроку("Отчёт сформирован: " + Формат(ТекущаяДата(), "ДЛФ=DT"));
Запись.ЗаписатьСтроку("Строк в выборке: " + Формат(1250, "ЧГ=0"));
Запись.Закрыть();
Обратите внимание на Формат(..., "ЧГ=0"). Без него число 1250 превратится в строку с неразрывным пробелом-разделителем групп: «1 250». Внешняя программа такое значение как число не прочитает.
Разница между Записать и ЗаписатьСтроку
- 📝
Записать("А"), затемЗаписать("Б")— в файле будетАБв одной строке. - 📄
ЗаписатьСтроку("А"), затемЗаписатьСтроку("Б")— две строки, после каждой перевод строки.
Последняя строка файла тоже получит перевод строки. Если принимающая сторона этого не любит, последнюю строку пишите методом Записать().
Примеры кода под разные задачи
Дописать строку в лог
Четвёртый параметр Истина — и новые строки встанут в конец файла, старые не пропадут. Если файла ещё нет, он создастся.
Процедура ЗаписатьВЛог(ТекстСообщения) Экспорт
ИмяЛога = "C:\Logs\exchange.log";
Строка = Формат(ТекущаяДата(), "ДФ='yyyy-MM-dd HH:mm:ss'") + " | " + ТекстСообщения;
Запись = Новый ЗаписьТекста(ИмяЛога, КодировкаТекста.UTF8, , Истина);
Запись.ЗаписатьСтроку(Строка);
Запись.Закрыть();
КонецПроцедуры
При дописывании указывайте ту же кодировку, что и при первом создании файла. Иначе в одном файле окажутся строки в разных кодировках, и половина будет «кракозябрами».
Выгрузить таблицу в CSV
Разделитель — точка с запятой: так файл в русской локали корректно открывается в Excel.
Запрос = Новый Запрос(
"ВЫБРАТЬ
| Номенклатура.Код КАК Код,
| Номенклатура.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| НЕ Номенклатура.ЭтоГруппа");
Выборка = Запрос.Выполнить().Выбрать();
Запись = Новый ЗаписьТекста("C:\Exchange\nomenklatura.csv", "windows-1251");
Запись.ЗаписатьСтроку("Код;Наименование");
Пока Выборка.Следующий() Цикл
Наименование = СтрЗаменить(Выборка.Наименование, ";", ",");
Запись.ЗаписатьСтроку(СокрЛП(Выборка.Код) + ";" + Наименование);
КонецЦикла;
Запись.Закрыть();
СтрЗаменить убирает точку с запятой из наименования. Без этого строка «Болт М6; оцинк.» разъедется на лишнюю колонку.
Записать через ТекстовыйДокумент
Удобно, когда текст нужно сначала собрать, а потом показать пользователю или сохранить.
Текст = Новый ТекстовыйДокумент;
Текст.ДобавитьСтроку("Первая строка");
Текст.ДобавитьСтроку("Вторая строка");
Текст.Записать("C:\Exchange\notes.txt", КодировкаТекста.ANSI);
На клиенте в тонком клиенте синхронный Записать может быть запрещён режимом совместимости конфигурации без модальности. Тогда используйте асинхронный вариант НачатьЗапись() с обработчиком оповещения.
UTF-8 без BOM
КодировкаТекста.UTF8 всегда пишет в начало файла BOM. Многие веб-сервисы, PHP-скрипты и Linux-утилиты его не ждут: первый заголовок CSV у них «портится». Чистый UTF-8 получают через двоичные данные:
Текст = "Код;Наименование" + Символы.ВК + Символы.ПС + "001;Стол";
Данные = ПолучитьДвоичныеДанныеИзСтроки(Текст, КодировкаТекста.UTF8, Ложь);
Данные.Записать("C:\Exchange\clean_utf8.csv");
Третий параметр Ложь отключает BOM. Перевод строки здесь ставится вручную, поэтому формат ВК+ПС или только ПС выбираете сами.
Обработка ошибок при записи файла
Запись в файл — одна из самых частых точек падения обработок. Каталога нет, нет прав, файл открыт в другой программе. Без обработки исключения пользователь увидит системное окно с ошибкой, а файл останется заблокированным до конца сеанса.
Запись = Неопределено;
Попытка
Запись = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.UTF8);
Для Каждого СтрокаТЧ Из Данные Цикл
Запись.ЗаписатьСтроку(СтрокаТЧ.Текст);
КонецЦикла;
Запись.Закрыть();
Исключение
Если Запись <> Неопределено Тогда
Запись.Закрыть();
КонецЕсли;
ЗаписьЖурналаРегистрации("Выгрузка в файл", УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение "Не удалось записать файл " + ИмяФайла + ". Подробности в журнале регистрации.";
КонецПопытки;
Главное в этом шаблоне — закрыть объект в ветке исключения. Если ошибка случилась на середине цикла, без Закрыть() файл повиснет открытым.
Откуда берутся ошибки и что проверить
Проверить, есть ли каталог, можно до записи:
Каталог = Новый Файл("C:\Exchange");
Если Не Каталог.Существует() Тогда
СоздатьКаталог("C:\Exchange");
КонецЕсли;
Запись файла на сервере и в веб-клиенте
Здесь путаются чаще всего. Код в процедуре с директивой &НаСервере работает на машине сервера 1С. Путь C:\Exchange\out.txt — это диск сервера, а не компьютер бухгалтера.
| Где выполняется код | Куда ляжет файл | Ограничения |
|---|---|---|
&НаКлиенте, тонкий клиент | Диск компьютера пользователя | Синхронные методы могут быть запрещены, нужны асинхронные |
&НаСервере, клиент-серверная база | Диск сервера 1С | Права пользователя службы, путь в формате ОС сервера |
&НаСервере, файловая база | Компьютер, где запущен клиент | Исключение — файловая база, опубликованная на веб-сервере: файл ляжет на веб-сервер |
&НаКлиенте, веб-клиент | Прямой записи нет | Только передача файла браузеру |
Как отдать файл пользователю из веб-клиента
Схема одна для веб-клиента и для тонкого клиента в клиент-серверной базе, когда файл нужен пользователю, а не серверу:
- На сервере формируете текст и превращаете его в
ДвоичныеДанные. - Кладёте данные во временное хранилище:
ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор). - На клиенте передаёте адрес хранилища в метод получения файла. Браузер покажет стандартное окно сохранения.
&НаСервере
Функция ПодготовитьФайл()
Текст = "Строка 1" + Символы.ВК + Символы.ПС + "Строка 2";
Данные = ПолучитьДвоичныеДанныеИзСтроки(Текст, КодировкаТекста.UTF8);
Возврат ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор);
КонецФункции
&НаКлиенте
Процедура СохранитьФайл(Команда)
Адрес = ПодготовитьФайл();
ПараметрыДиалога = Новый ПараметрыДиалогаПолученияФайлов;
НачатьПолучениеФайлаССервера(Адрес, "export.txt", ПараметрыДиалога);
КонецПроцедуры
Метод НачатьПолучениеФайлаССервера есть в актуальных версиях платформы 8.3. В конфигурациях на БСП (БП 3.0, ЗУП 3.1, УТ 11) принято вызывать обёртку ФайловаяСистемаКлиент.СохранитьФайл: она сама учитывает тип клиента и расширение работы с файлами.
Если на сервере писали во временный файл, удалите его после чтения: УдалитьФайлы(ИмяВременногоФайла). Иначе временный каталог сервера за месяцы обрастёт тысячами мусорных файлов.
Сервер на Linux
На Linux пути пишутся через прямой слеш: /var/exchange/out.txt. Регистр в имени файла имеет значение, Out.txt и out.txt — разные файлы. Пользователю, от имени которого работает сервер 1С, нужны права на запись в каталог.
Частые ошибки и как их избежать
- ❌ Запись в цикле с открытием файла на каждой итерации. Создать
ЗаписьТекстаодин раз до цикла и закрыть после — в разы быстрее, чем дописывать по строке с переоткрытием. - ❌
ТекстовыйДокументдля выгрузки на миллион строк. Весь текст живёт в памяти процесса. На сервере это лишняя нагрузка на рабочий процесс, лучше потоковаяЗаписьТекста. - ❌ Склейка числа со строкой без
Формат(). Получите разделители групп и запятую вместо точки там, где внешняя система ждёт1250.50. Для дробных —Формат(Сумма, "ЧРД=.; ЧГ=0"). - ❌ Жёстко прописанный путь
C:\...в серверном коде. Сегодня сервер на Windows, завтра переехали на Linux — обработка сломается. Путь выносите в константу или настройку.