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

· 9 мин

Содержание

Записать текстовый файл в 1С проще всего объектом ЗаписьТекста: создаёте его с именем файла и кодировкой, вызываете ЗаписатьСтроку() нужное число раз и обязательно Закрыть(). Три строки кода, и файл на диске. Тема общая для платформы 8.3, от конфигурации не зависит: в БП, ЗУП, УТ и в своей обработке всё работает одинаково.

Частое заблуждение — что файл появится на компьютере пользователя, где бы ни выполнялся код. Нет. Если запись идёт в серверной процедуре, файл ляжет на диск сервера 1С. А в веб-клиенте прямой записи на локальный диск нет вообще: файл готовят на сервере и передают браузеру. Поэтому сначала решите, где выполняется код, и только потом выбирайте путь к файлу.

Чем писать текст в файл: три объекта платформы

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

ОбъектКак работаетКогда брать
ЗаписьТекстаПишет строку за строкой прямо в файл, в памяти ничего не копитЛоги, большие выгрузки, CSV на сотни тысяч строк
ТекстовыйДокументСобирает весь текст в памяти, потом сохраняет одним вызовомНебольшой текст, который нужно ещё и показать пользователю или отредактировать
ДвоичныеДанныеСтрока превращается в байты и записывается целикомНужен точный контроль над байтами: UTF-8 без BOM, передача файла клиенту

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

Простое правило: пишете много и построчно — ЗаписьТекста. Нужно показать результат на экране — ТекстовыйДокумент. Нужен файл «байт в байт» под чужую систему — ДвоичныеДанные.

Кодировка и режим записи: что указать в параметрах

Конструктор ЗаписьТекста принимает до пяти параметров:

Запись = Новый ЗаписьТекста(ИмяФайла, Кодировка, РазделительСтрок, Дописывание, РазделительСтрокВФайле);
  1. ИмяФайла — полный путь, например C:\Exchange\out.txt.
  2. Кодировка — значение системного перечисления КодировкаТекста или строка с именем кодировки.
  3. РазделительСтрок — какой символ в строках 1С считать концом строки. Обычно не указывают.
  4. Дописывание — Истина, чтобы добавлять в конец существующего файла; Ложь (по умолчанию) — перезаписать.
  5. РазделительСтрокВФайле — чем разделять строки в самом файле. По умолчанию это пара символов ВК+ПС, как принято в Windows.

Какую кодировку выбрать

ЗначениеЧто получитсяДля чего
КодировкаТекста.UTF8UTF-8 с BOM (три служебных байта в начале)Современные системы, кириллица без потерь
КодировкаТекста.ANSIWindows-1251 на русской WindowsСтарые программы, Excel при открытии CSV двойным щелчком
КодировкаТекста.OEMКодовая страница 866Файлы для консоли и bat-скриптов
КодировкаТекста.UTF16UTF-16Редко, по требованию принимающей стороны
КодировкаТекста.СистемнаяКодировка операционной системы сервера или клиентаКогда файл читает программа на той же машине

Если кодировку не указать, платформа запишет файл в UTF-8. Для обмена с внешними системами это не всегда то, что нужно: многие старые программы ждут Windows-1251, а некоторые парсеры спотыкаются о BOM.

КодировкаТекста.ANSI зависит от настроек ОС. На Linux-сервере 1С «ANSI» — это не обязательно Windows-1251. Если файл уходит во внешнюю систему, надёжнее указать кодировку явно строкой: "windows-1251".

Пошаговая запись текстового файла через ЗаписьТекста

Минимальный рабочий порядок:

  1. Определите, где выполняется код: на клиенте или на сервере. От этого зависит, на чей диск ляжет файл.
  2. Сформируйте путь. Для временных файлов используйте ПолучитьИмяВременногоФайла("txt") — платформа сама подберёт каталог и уникальное имя.
  3. Создайте объект ЗаписьТекста с нужной кодировкой.
  4. Пишите данные: ЗаписатьСтроку() добавляет текст и перевод строки, Записать() — только текст.
  5. Вызовите Закрыть(). До этого файл может быть заблокирован, а часть данных не сброшена на диск.
ИмяФайла = "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. Кладёте данные во временное хранилище: ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор).
  3. На клиенте передаёте адрес хранилища в метод получения файла. Браузер покажет стандартное окно сохранения.
&НаСервере
Функция ПодготовитьФайл()
    Текст = "Строка 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 — обработка сломается. Путь выносите в константу или настройку.

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

Можно ли записать файл в кодировке, которой нет в перечислении КодировкаТекста?
Да. Вторым параметром передайте строку с именем кодировки, например «koi8-r» или «windows-1251». Платформа поддерживает стандартные имена кодировок.
Как прочитать файл, который только что записал?
Объектом ЧтениеТекста с той же кодировкой или методом Прочитать() у ТекстовыйДокумент. Метод ПрочитатьСтроку() возвращает Неопределено, когда строки закончились.
Почему файл пустой, хотя ошибок не было?
Скорее всего, не вызван Закрыть() или код выполнился на другой машине: на сервере вместо клиента. Проверьте директиву процедуры и наличие вызова Закрыть().
Можно ли писать один файл из нескольких сеансов одновременно?
Надёжно нельзя: строки могут перемешаться или запись упадёт на блокировке. Для общего лога лучше журнал регистрации или отдельный файл на каждый сеанс.
Чем ЗаписьТекста отличается от ЗаписьXML и ЗаписьJSON?
ЗаписьТекста пишет произвольный текст как есть. ЗаписьXML и ЗаписьJSON сами формируют разметку, экранируют спецсимволы и следят за структурой. Для XML и JSON используйте их.