Как читать и записывать текстовый файл из кода 1С
Содержание
Для небольшого файла берите ТекстовыйДокумент: он целиком грузит содержимое в память, дальше строки доступны по номеру. Для файла в десятки мегабайт берите ЧтениеТекста и читайте построчно. Писать удобнее через ЗаписьТекста, когда строк много и порядок важен.
Кодировку всегда указывайте явно. Именно из-за неё «кракозябры» появляются чаще всего: файл из банка или чужой программы почти никогда не бывает в той кодировке, которую 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-разрядном процессе такая загрузка упирается в потолок адресного пространства, и сеанс падает.
Чтение через ЧтениеТекста построчно держит в памяти одну строку. Для почти любой задачи этого достаточно.
Что ускоряет обработку
- Читайте и пишите на сервере, а не гоняйте строки между клиентом и сервером. Каждый серверный вызов стоит времени.
- Не конкатенируйте результат в цикле строкой
Результат = Результат + Строка. На миллионе строк это копирование памяти по кругу. Пишите сразу вЗаписьТекстаили копите в массив и склеивайтеСтрСоединить. - Разбирайте только нужные строки: сначала проверка по префиксу через
СтрНачинаетсяС, потом полный разбор. - Пакетно записывайте результат в базу: набор записей регистра целиком, а не по одной записи с транзакцией на каждую.
- Показывайте прогресс не на каждой строке, а раз в 1000-5000 строк. Обновление индикатора само по себе дорого.
Файл не влезает в разумное время
Если обработка идёт часами, вынесите её в регламентное задание или фоновое задание, чтобы пользователь не сидел перед зависшим окном. Для разбивки используйте счётчик строк: каждые N строк фиксируйте транзакцию и запоминайте позицию, чтобы при сбое продолжить, а не начинать заново.
Когда файл по сути табличный (CSV на сотни тысяч строк), оцените, не удобнее ли загрузить его во внешнюю таблицу СУБД или конвертировать заранее. Это решение за пределами 1С, но иногда оно сокращает час работы до минут.
Типичные ошибки при работе с текстовыми файлами
ЧтениеТекста или ЗаписьТекста. Закрывайте объект в Закрыть() и в ветке обработки исключения: оберните работу в Попытка … Исключение … КонецПопытки и закрывайте объект в обеих ветках.ПрочитатьСтроку() на Неопределено, а не на пустую строку.Ещё две ловушки, которые не попали в таблицу:
- ⚠️ Права на каталог. Служба сервера 1С запускается от своего пользователя Windows, и у него может не быть доступа к сетевой папке, хотя вы вручную открываете её без проблем. Сетевые диски, подключённые «буквой» у вашего пользователя, у службы вообще не видны. Указывайте полный UNC-путь.
- ⚠️ Длинные пути и недопустимые символы в имени файла. Двоеточие, звёздочка и вопросительный знак в имени из названия контрагента сломают запись. Чистите имя перед созданием файла.
Мини-проверка перед выгрузкой
Частые вопросы
Как прочитать файл в 1С, если я не знаю его кодировку?
Чем ТекстовыйДокумент отличается от ЧтениеТекста?
Можно ли изменить одну строку в файле, не переписывая его целиком?
ТекстовыйДокумент, замените строку через ЗаменитьСтроку и запишите обратно. Для огромных файлов читайте один и пишите во второй временный, потом подменяйте.Как сделать, чтобы запись не затирала старое содержимое?
ЗаписьТекста признак добавления Истина. Тогда новые строки пойдут в конец существующего файла.