Как читать и записывать текстовый файл из кода 1С

· 9 мин

Содержание

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

Кодировку всегда указывайте явно. Именно из-за неё «кракозябры» появляются чаще всего: файл из банка или чужой программы почти никогда не бывает в той кодировке, которую 1С выберет сама.

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

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

ОбъектКогда братьОграничения
ТекстовыйДокументНебольшой файл, нужен доступ к строке по номеру, правка «на месте»Весь файл в оперативной памяти
ЧтениеТекстаПоследовательное чтение, большие файлы, разбор по строкамТолько вперёд, без доступа по номеру
ЗаписьТекстаВыгрузка в файл, дозапись в конец, журналыТолько запись, прочитать обратно нельзя

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

Где выполняется код

Файл читается там, где запущен код. На сервере вы получаете доступ к дискам сервера, на клиенте — к дискам компьютера пользователя. Путь C:\Обмен\data.txt в серверной процедуре означает диск C: самого сервера.

Если пользователь выбирает файл на своём компьютере, а обрабатывать его нужно на сервере, файл сначала передают на сервер. Для этого есть диалог выбора файла и помещение файла во временное хранилище. Подробности ищите в синтакс-помощнике по методам помещения файлов.

В файловой базе клиент и сервер часто совпадают, поэтому путь «работает у меня». В клиент-серверном варианте тот же код падает: сервер не видит диск пользователя.

Читаем данные из текстового файла

Через ТекстовыйДокумент

Самый короткий вариант. Читаем файл и обходим строки:

Документ = Новый ТекстовыйДокумент;
Документ.Прочитать("C:\Обмен\data.txt", КодировкаТекста.UTF8);

Для Номер = 1 По Документ.КоличествоСтрок() Цикл
    Строка = Документ.ПолучитьСтроку(Номер);
    // обработка строки
КонецЦикла;

Нумерация строк идёт с единицы. Метод ПолучитьТекст() вернёт всё содержимое одной строкой с переносами, когда нужно передать текст дальше целиком.

💡 Если файл может не существовать, сначала проверьте это через объект Файл и его метод Существует(). Без проверки получите исключение на Прочитать.

Через ЧтениеТекста

Этот способ экономит память: в ней находится только текущая строка.

Чтение = Новый ЧтениеТекста("C:\Обмен\data.txt", КодировкаТекста.UTF8);

Строка = Чтение.ПрочитатьСтроку();
Пока Строка <> Неопределено Цикл
    // обработка строки
    Строка = Чтение.ПрочитатьСтроку();
КонецЦикла;

Чтение.Закрыть();

Признак конца файла — значение Неопределено. Пустая строка "" — это просто пустая строка внутри файла, цикл на ней останавливать нельзя.

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

Если нужно сразу всё содержимое одной переменной, у ЧтениеТекста есть метод Прочитать(). Он вернёт весь оставшийся текст целиком.

Разбор строки на поля

Банковские выписки и выгрузки из учётных систем обычно устроены как «поля через разделитель». Разбирайте строку функцией СтрРазделить:

Поля = СтрРазделить(Строка, ";", Ложь);
Если Поля.Количество() < 3 Тогда
    Продолжить;
КонецЕсли;
Контрагент = СокрЛП(Поля[0]);

Последний параметр Ложь означает «не включать пустые подстроки». Если пустые поля в файле значимы (скажем, пропущен ИНН), передайте Истина, иначе индексы полей поедут.

Для файла с фиксированной шириной колонок используйте Сред(Строка, Начало, Длина). Позиции берите из описания формата, а не «на глаз» по образцу.

Чтение только нужной части файла

Не всегда нужен весь файл. Бывает, что в выгрузке важна лишь шапка или несколько строк с итогами. Тогда читайте через ЧтениеТекста и выходите из цикла, как только нашли своё:

Пока Строка <> Неопределено Цикл
    Если СтрНачинаетсяС(Строка, "ИТОГО") Тогда
        Итог = Строка;
        Прервать;
    КонецЕсли;
    Строка = Чтение.ПрочитатьСтроку();
КонецЦикла;

Так вы не тратите время на хвост файла, который не понадобится. Закрыть объект после Прервать всё равно нужно.

Поиск и замена внутри текста

Когда файл небольшой, проще всего загрузить его одной строкой и поработать строковыми функциями: СтрЗаменить меняет все вхождения, СтрНайти возвращает позицию, СтрЧислоСтрок считает строки. Например, выгрузку, где десятичный разделитель — запятая, перед разбором приводят к точке: СтрЗаменить(Текст, ",", "."). Но только если запятая не служит ещё и разделителем полей, иначе сломаете структуру.

Когда нужен поток байтов

ЧтениеДанных и ЗаписьДанных берут на себя то, что текстовые объекты не умеют: чтение заданного числа байтов, разбор бинарных заголовков, работу с файлами смешанного содержимого. Если файл «почти текстовый», но внутри есть бинарные вставки, начните с потока, а текстовые фрагменты преобразуйте отдельно через нужную кодировку.

Запись и создание текстового файла

Новый файл через ЗаписьТекста

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

Запись.ЗаписатьСтроку("Заголовок");
Для Каждого Элемент Из МассивДанных Цикл
    Запись.ЗаписатьСтроку(Элемент);
КонецЦикла;

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

ЗаписатьСтроку сама добавляет перевод строки в конце. Метод Записать пишет текст как есть, без разделителя.

Если файл уже существует, он будет перезаписан. Вы не получите предупреждения.

Дозапись в конец

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

Запись = Новый ЗаписьТекста("C:\Обмен\log.txt", КодировкаТекста.UTF8, , Истина);
Запись.ЗаписатьСтроку(ТекущаяДата() + ": загрузка завершена");
Запись.Закрыть();

Пропущенный третий параметр оставляет разделитель по умолчанию. Если первой строкой в файле уже есть что-то, дозапись продолжит с конца, а не с начала.

Через ТекстовыйДокумент

Когда текст уже собран в документе, достаточно одного вызова:

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

Удобно, пока строк немного. Для сотен тысяч строк документ держит всё в памяти до самой записи, и тут лучше ЗаписьТекста.

Временные файлы

Промежуточные данные пишите во временный файл, а не в произвольную папку: ПолучитьИмяВременногоФайла() выдаёт уникальный путь в системной временной директории. После работы удаляйте файл через УдалитьФайлы.

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

Кодировки и «кракозябры»: как выбрать правильную

Откройте файл в обычном текстовом редакторе, который показывает кодировку (например, в Notepad++). Это быстрее, чем гадать. Если вместо русских букв видите «РџСЂРёРІРµС‚» — файл в UTF-8, а прочитан как ANSI. Если видите «Ïðèâåò» — наоборот, файл в Windows-1251, а читали как UTF-8.

В платформе кодировки задаются перечислением КодировкаТекста, либо строкой с названием.

КодировкаТипичный источник
КодировкаТекста.UTF8Современные выгрузки, веб-сервисы, JSON
КодировкаТекста.ANSIСтарые программы Windows (в русской системе это Windows-1251)
КодировкаТекста.OEMКонсольные утилиты, .bat-файлы, DOS-программы
КодировкаТекста.UTF16Некоторые выгрузки Windows-приложений

BOM: невидимые три байта

Файл в UTF-8 может начинаться с метки порядка байтов (BOM). Платформа при чтении обычно её распознаёт и в строку не включает. Но сторонние программы бывают к ней чувствительны: загрузчик банк-клиента может отвергнуть файл с BOM или, наоборот, потребовать его.

При записи платформа в ряде случаев добавляет BOM сама. Нужен файл без метки? В синтакс-помощнике посмотрите описание конструктора ЗаписьТекста для вашей версии платформы: там указано, как управлять записью BOM.

💡 Проверка на практике: запишите тестовый файл и откройте его в шестнадцатеричном просмотрщике. Три первых байта EF BB BF означают UTF-8 с BOM.

Спецсимволы и разделители строк

  • 🔹 Файлы из Windows используют пару «возврат каретки + перевод строки», из Linux — только перевод строки. ЧтениеТекста обрабатывает оба варианта.
  • 🔹 Табуляцию в тексте обозначайте константой Символы.Таб, перевод строки — Символы.ПС.
  • 🔹 Неразрывный пробел (код 160) выглядит как обычный, но СокрЛП его не убирает. Если сравнение строк «внезапно» не срабатывает, проверьте именно его через КодСимвола.
  • 🔹 Знак 0 в середине файла говорит о том, что перед вами не текст, а бинарные данные или UTF-16, прочитанный как однобайтовый.

Большие файлы: как не съесть память и время

Файл в 300 МБ через ТекстовыйДокумент превращается в сотни мегабайт в памяти плюс накладные расходы на строки. На 32-разрядном процессе такая загрузка упирается в потолок адресного пространства, и сеанс падает.

Чтение через ЧтениеТекста построчно держит в памяти одну строку. Для почти любой задачи этого достаточно.

Что ускоряет обработку

  1. Читайте и пишите на сервере, а не гоняйте строки между клиентом и сервером. Каждый серверный вызов стоит времени.
  2. Не конкатенируйте результат в цикле строкой Результат = Результат + Строка. На миллионе строк это копирование памяти по кругу. Пишите сразу в ЗаписьТекста или копите в массив и склеивайте СтрСоединить.
  3. Разбирайте только нужные строки: сначала проверка по префиксу через СтрНачинаетсяС, потом полный разбор.
  4. Пакетно записывайте результат в базу: набор записей регистра целиком, а не по одной записи с транзакцией на каждую.
  5. Показывайте прогресс не на каждой строке, а раз в 1000-5000 строк. Обновление индикатора само по себе дорого.

Файл не влезает в разумное время

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

Когда файл по сути табличный (CSV на сотни тысяч строк), оцените, не удобнее ли загрузить его во внешнюю таблицу СУБД или конвертировать заранее. Это решение за пределами 1С, но иногда оно сокращает час работы до минут.

Типичные ошибки при работе с текстовыми файлами

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

Ещё две ловушки, которые не попали в таблицу:

  • ⚠️ Права на каталог. Служба сервера 1С запускается от своего пользователя Windows, и у него может не быть доступа к сетевой папке, хотя вы вручную открываете её без проблем. Сетевые диски, подключённые «буквой» у вашего пользователя, у службы вообще не видны. Указывайте полный UNC-путь.
  • ⚠️ Длинные пути и недопустимые символы в имени файла. Двоеточие, звёздочка и вопросительный знак в имени из названия контрагента сломают запись. Чистите имя перед созданием файла.

Мини-проверка перед выгрузкой

Перед запуском выгрузки в файл
Выполнено: 0 / 6

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

Как прочитать файл в 1С, если я не знаю его кодировку?
Платформа сама определить её надёжно не умеет. Откройте файл в редакторе с показом кодировки. Если такого нет, попробуйте UTF-8 и ANSI по очереди: неверный вариант сразу даёт нечитаемый текст в первых строках.
Чем ТекстовыйДокумент отличается от ЧтениеТекста?
Первый загружает файл целиком и даёт доступ к любой строке по номеру. Второй читает последовательно и почти не занимает память. Для больших файлов берите второй.
Можно ли изменить одну строку в файле, не переписывая его целиком?
Нет, текстовый файл так не работает. Загрузите в ТекстовыйДокумент, замените строку через ЗаменитьСтроку и запишите обратно. Для огромных файлов читайте один и пишите во второй временный, потом подменяйте.
Как сделать, чтобы запись не затирала старое содержимое?
Передайте в конструктор ЗаписьТекста признак добавления Истина. Тогда новые строки пойдут в конец существующего файла.
Почему код работает на моём компьютере и не работает у пользователей?
Чаще всего причина в том, что код выполняется на сервере, а путь указывает на локальный диск. Проверьте, где запущена процедура: на клиенте или на сервере.