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