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

· 9 мин

Содержание

Чтобы записать текст в файл в 1С, создайте Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.UTF8), вызовите ЗаписатьСтроку() для каждой строки и закройте объект методом Закрыть(). Если весь текст уже собран в одну переменную, хватит трёх строк с ТекстовыйДокумент: создать, УстановитьТекст(), Записать().

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

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

Способов пять, и они не взаимозаменяемы. Выбор зависит от объёма, кодировки и того, нужно ли дописывать в конец.

СпособКогда братьОграничения
ТекстовыйДокументНебольшой текст, который удобно собрать целикомВесь текст держится в памяти
ЗаписьТекстаПострочная выгрузка, логи, дозаписьПишет BOM в UTF-8
ФайловыеПотоки + ЗаписьДанныхБольшие файлы, UTF-8 без BOM, бинарные вставкиПлатформа 8.3.9 и новее
ДвоичныеДанные из строкиГотовая строка, точный контроль BOMСтрока целиком в памяти
COM (Scripting.FileSystemObject, ADODB.Stream)Унаследованный код, особые кодировкиТолько Windows

💡 Для новых разработок разумный выбор по умолчанию — ЗаписьТекста. К COM стоит идти, только когда встроенных средств правда не хватает.

Где физически окажется файл

Это первый вопрос, который надо решить до кода. Код в модуле с директивой &НаСервере пишет файл на диск сервера 1С, а не на компьютер пользователя. В клиент-серверной базе путь C:\Выгрузка\отчёт.txt окажется на сервере, и бухгалтер его не увидит.

Правильная схема для выгрузки пользователю:

  1. На сервере сформируйте текст во временный файл: ПолучитьИмяВременногоФайла("txt").
  2. Прочитайте его в ДвоичныеДанные и поместите во временное хранилище: ПоместитьВоВременноеХранилище().
  3. Удалите временный файл через УдалитьФайлы().
  4. На клиенте отдайте файл пользователю. В типовых конфигурациях на БСП для этого есть ФайловаяСистемаКлиент.СохранитьФайл().

Серверная часть такой выгрузки выглядит так:

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

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

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

Записать текст в файл через ТекстовыйДокумент

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

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

Если строка уже готова, вместо ДобавитьСтроку() используйте УстановитьТекст(Строка). Переносы Символы.ПС внутри строки станут переносами в файле.

Метод Записать() принимает третьим параметром разделитель строк. Для файлов, которые потом читает Linux-система или веб-сервис, передайте Символы.ПС, иначе в Windows по умолчанию получите ВК + ПС.

⚠️ ТекстовыйДокумент.Записать() перезаписывает файл целиком. Для дозаписи в конец он не подходит: прочитать, добавить и записать заново на больших файлах медленно и опасно при параллельной работе.

Запись без BOM через двоичные данные

Некоторые банки, сайты и сервисы не принимают UTF-8 с меткой порядка байтов в начале. Самый короткий способ записать текст без неё:

Данные = ПолучитьДвоичныеДанныеИзСтроки(Текст, КодировкаТекста.UTF8, Ложь);
Данные.Записать("C:\Обмен\upload.json");

Третий параметр Ложь отключает BOM. Функция доступна в платформе 8.3.9 и новее.

Построчная запись и дозапись через ЗаписьТекста

ЗаписьТекста пишет в файл по мере работы и не держит весь текст в памяти. Это основной инструмент для выгрузок и логов.

Параметры конструктора по порядку:

  • 📄 имя файла;
  • 🔤 кодировка (КодировкаТекста.UTF8, КодировкаТекста.ANSI или строка, например "windows-1251");
  • ↩️ разделитель строк, который вы используете в тексте;
  • ➕ признак дописывания: Истина — добавлять в конец, Ложь — перезаписать;
  • 💾 разделитель строк в файле.
Запись = Новый ЗаписьТекста("C:\Обмен\контрагенты.txt", КодировкаТекста.UTF8);

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    Запись.ЗаписатьСтроку(Выборка.Наименование + Символы.Таб + Выборка.ИНН);
КонецЦикла;

Запись.Закрыть();

Разница методов: ЗаписатьСтроку() добавляет перенос после текста, Записать() — нет. Последним удобно собирать одну строку из нескольких кусков.

Чтобы дописать строку в существующий файл, передайте четвёртый параметр:

Запись = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.UTF8, , Истина);

Если каталога ещё нет

ЗаписьТекста не создаёт папки по пути. Если каталога нет, конструктор упадёт с исключением. Проверьте и создайте его заранее:

Каталог = Новый Файл("C:\Обмен\2025-05");
Если Не Каталог.Существует() Тогда
    СоздатьКаталог(Каталог.ПолноеИмя);
КонецЕсли;

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

Всегда вызывайте Закрыть(). Пока объект открыт, файл заблокирован, а последние строки могут остаться в буфере и не попасть на диск.

Потоки и ЗаписьДанных для больших файлов

С версии 8.3.9 в платформе есть файловые потоки. Они нужны, когда файл огромный, когда в один файл пишут и текст, и двоичные блоки, или когда нужен UTF-8 без BOM при построчной записи.

Поток = ФайловыеПотоки.ОткрытьДляЗаписи("C:\Обмен\остатки.txt");
Запись = Новый ЗаписьДанных(Поток, КодировкаТекста.UTF8);

Для Каждого Строка Из ТаблицаОстатков Цикл
    Запись.ЗаписатьСтроку(Строка.Артикул + ";" + Формат(Строка.Остаток, "ЧГ=0"));
КонецЦикла;

Запись.Закрыть();
Поток.Закрыть();

ЗаписьДанных не ставит BOM в начало файла. Для дозаписи откройте поток через ФайловыеПотоки.ОткрытьДляДописывания(ИмяФайла).

💡 Порядок закрытия важен: сначала объект записи, потом поток. Иначе часть данных из буфера записи потеряется.

Выгрузка таблицы в CSV из 1С

CSV — тот же текстовый файл, но с правилами. Excel в русской локали ждёт разделитель «точка с запятой», а не запятую.

Три правила, без которых файл откроется криво:

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

Запись = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.UTF8);
Запись.ЗаписатьСтроку("""Дата"";""Номер"";""Сумма""");
Для Каждого Стр Из ТаблицаДокументов Цикл
    Запись.ЗаписатьСтроку(ПолеCSV(Стр.Дата) + ";" + ПолеCSV(Стр.Номер) + ";" + ПолеCSV(Стр.Сумма));
КонецЦикла;
Запись.Закрыть();

Дробные суммы Формат выведет с запятой, как и ждёт русский Excel. Если файл уходит в программу, которая ждёт точку, добавьте в строку формата ЧРД=..

Про кодировку. Excel открывает UTF-8 без искажения кириллицы, только если в начале есть BOM. ЗаписьТекста с КодировкаТекста.UTF8 его ставит, так что файл из примера откроется нормально. Для старых программ, которые не понимают UTF-8, укажите КодировкаТекста.ANSI.

COM-объекты Windows и внешние компоненты

COM нужен редко, но встречается в старом коде и в задачах, где встроенных кодировок не хватает. Работает только на Windows. При записи на сервере у учётной записи службы 1С должны быть права на каталог.

Дозапись через Scripting.FileSystemObject:

ФС = Новый COMОбъект("Scripting.FileSystemObject");
Файл = ФС.OpenTextFile("C:\Логи\обмен.log", 8, Истина);
Файл.WriteLine("Обмен завершён");
Файл.Close();

Число 8 означает режим дописывания, Истина — создать файл, если его нет. Учтите: FileSystemObject в этом режиме пишет в ANSI, а не в UTF-8.

UTF-8 без BOM или нестандартная кодировка — через ADODB.Stream:

Поток = Новый COMОбъект("ADODB.Stream");
Поток.Type = 2;
Поток.Charset = "koi8-r";
Поток.Open();
Поток.WriteText(Текст);
Поток.SaveToFile("C:\Обмен\старый_формат.txt", 2);
Поток.Close();

Параметр 2 в SaveToFile разрешает перезапись существующего файла.

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

ЗадачаВстроенный языкCOM
UTF-8 с BOMЗаписьТекстаADODB.Stream
UTF-8 без BOMЗаписьДанных, ПолучитьДвоичныеДанныеИзСтрокиADODB.Stream + обрезка BOM
windows-1251КодировкаТекста.ANSIFileSystemObject
Работа на Linux-сервереДаНет

Лог-файл: дозапись строк и ротация

Текстовый лог удобен для отладки обменов и регламентных заданий. Пример процедуры с дозаписью и простой ротацией по размеру:

Процедура ЗаписатьВЛог(ТекстСообщения) Экспорт
    ИмяЛога = "C:\Логи\обмен.log";
    ПределБайт = 10 * 1024 * 1024; // 10 МБ

    Файл = Новый Файл(ИмяЛога);
    Если Файл.Существует() И Файл.Размер() > ПределБайт Тогда
        Архив = "C:\Логи\обмен_" + Формат(ТекущаяДатаСеанса(), "ДФ=yyyyMMdd_HHmmss") + ".log";
        ПереместитьФайл(ИмяЛога, Архив);
    КонецЕсли;

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

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

Старые архивы удаляйте отдельно, например раз в сутки регламентным заданием: НайтиФайлы("C:\Логи", "обмен_*.log") вернёт список, дальше удаляете файлы старше нужной даты.

⚠️ Если в один файл одновременно пишут несколько сеансов (фоновые задания, несколько пользователей), второй сеанс может получить ошибку открытия файла. Выходов два: отдельный файл на сеанс (добавьте в имя номер сеанса из НомерСеансаИнформационнойБазы()) или штатный ЗаписьЖурналаРегистрации(), который рассчитан на параллельную запись.

Ошибки, кодировки и безопасность при записи

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

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

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

Не полагайтесь на кодировку по умолчанию: указывайте её явно в каждом вызове. Тогда файл получится одинаковым и на Windows, и на Linux-сервере, и через год после смены платформы.

Получатель файлаЧто указать
Excel, открытие двойным щелчкомКодировкаТекста.UTF8 (с BOM)
Старая программа на Windows, банк-клиентКодировкаТекста.ANSI или "windows-1251"
Веб-сервис, JSON, сайтUTF-8 без BOM через ЗаписьДанных
Консольная утилита WindowsКодировкаТекста.OEM (кодовая страница 866)

Сомневаетесь, что получилось, — откройте файл в Notepad++: в строке состояния он покажет кодировку и наличие BOM.

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

Безопасный режим и пути от пользователя

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

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

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

Чем ЗаписьТекста отличается от ТекстовыйДокумент?
ТекстовыйДокумент держит весь текст в памяти и пишет его разом. ЗаписьТекста пишет на диск по мере работы и умеет дописывать в конец файла.
Как записать файл в кодировке windows-1251?
Передайте в конструктор КодировкаТекста.ANSI или строку "windows-1251". На русской Windows оба варианта дают кодировку 1251.
Можно ли записать файл прямо на компьютер пользователя из серверного кода?
Нет. Серверный код видит только диск сервера. Сформируйте двоичные данные, положите их во временное хранилище и сохраните файл на клиенте.
Как записать текст в файл на Linux-сервере 1С?
Так же, только путь в формате /var/1c/exchange/file.txt, а разделитель строк — Символы.ПС. COM-объекты на Linux недоступны.
Что быстрее для выгрузки миллиона строк?
ЗаписьТекста или поток с ЗаписьДанных. Собирать такой объём через ТекстовыйДокумент или конкатенацию одной строки — значит забить память сеанса.