Чтение txt, csv и логов во встроенном языке 1С 8.3
Содержание
Прочитать текстовый файл в 1С проще всего объектом ЧтениеТекста: создаёте его с путём и кодировкой, в цикле вызываете ПрочитатьСтроку(), пока она не вернёт Неопределено, и закрываете. Для небольшого файла, который нужен целиком, хватит метода Прочитать() того же объекта или ТекстовыйДокумент.
Типичная ситуация: банк прислал выписку в CSV, склад выгрузил остатки в txt, а внешняя программа пишет лог, который надо разобрать обработкой. Ниже код для каждого случая, разбор кодировок и обработка ошибок. Всё относится к платформе 1С:Предприятие 8.3 и не зависит от конфигурации: код работает в БП, ЗУП, УТ и любой своей обработке.
Какие объекты платформы читают текстовые файлы
В платформе 8.3 есть три основных инструмента. Они отличаются тем, сколько памяти тратят и что умеют.
- 📄
ЧтениеТекста— последовательное чтение файла или потока. Держит в памяти только текущую строку. Подходит для файлов любого размера. - 📝
ТекстовыйДокумент— загружает весь файл и даёт доступ к строке по номеру:ПолучитьСтроку(Номер),КоличествоСтрок(). Удобен, когда нужно вернуться назад или знать число строк заранее. - 🔀 Потоки и двоичные данные —
ДвоичныеДанные,ОткрытьПотокДляЧтения(), функцияПолучитьСтрокуИзДвоичныхДанных(). Нужны, когда файл пришёл не с диска сервера, а из временного хранилища, HTTP-ответа или вложения. Появились в 8.3.9.
Есть ещё объект Файл. Он сам ничего не читает, но проверяет, существует ли файл, и даёт его размер и имя. Его удобно вызывать перед чтением.
Где выполняется код, там и ищется файл. Путь C:\Обмен\остатки.txt в серверной процедуре ищется на сервере 1С, а не на компьютере бухгалтера. С этого и начинайте разбор ошибки «файл не найден».
Построчное чтение текстового файла: базовый алгоритм
Построчный обход — основной способ. Он не зависит от размера файла: лог на 2 ГБ читается так же, как файл на 10 строк.
Процедура ПрочитатьФайлПострочно(ИмяФайла)
Чтение = Новый ЧтениеТекста(ИмяФайла, КодировкаТекста.UTF8);
НомерСтроки = 0;
Строка = Чтение.ПрочитатьСтроку();
Пока Строка <> Неопределено Цикл
НомерСтроки = НомерСтроки + 1;
// Здесь обработка строки
Сообщить(СтрШаблон("%1: %2", НомерСтроки, Строка));
Строка = Чтение.ПрочитатьСтроку();
КонецЦикла;
Чтение.Закрыть();
КонецПроцедуры
Что здесь важно:
- Конец файла определяется по
Неопределено, а не по пустой строке. Пустая строка внутри файла вернётся как"", и цикл не прервётся раньше времени. - Первое чтение стоит до цикла, следующее — в конце тела цикла. Так последняя строка не потеряется и не обработается дважды.
Закрыть()освобождает файл. Без него файл остаётся занятым, пока объект не уничтожится, и другая программа не сможет его перезаписать.
Отбор нужных строк из лога
Из лога обычно нужны не все строки, а только ошибки. Фильтр ставится внутри того же цикла:
Если СтрНайти(ВРег(Строка), "ERROR") > 0 Тогда
НайденныеОшибки.Добавить(Строка);
КонецЕсли;
НайденныеОшибки — обычный Массив, созданный до цикла. ВРег() нужен, чтобы не пропустить Error и error. Для отбора по дате сравнивайте начало строки: Лев(Строка, 10) = "2026-10-07", если лог пишет дату в формате ГГГГ-ММ-ДД.
Разбор CSV по полям
CSV — та же построчная схема плюс разбиение строки. С 8.3.6 для этого есть СтрРазделить():
Процедура ЗагрузитьОстаткиИзCSV(ИмяФайла)
Чтение = Новый ЧтениеТекста(ИмяФайла, "windows-1251");
Заголовок = Чтение.ПрочитатьСтроку(); // первую строку с названиями колонок пропускаем
Строка = Чтение.ПрочитатьСтроку();
Пока Строка <> Неопределено Цикл
Если ПустаяСтрока(Строка) Тогда
Строка = Чтение.ПрочитатьСтроку();
Продолжить;
КонецЕсли;
Поля = СтрРазделить(Строка, ";", Истина);
Артикул = СокрЛП(Поля[0]);
Наименование = СокрЛП(Поля[1]);
КоличествоСтрокой = СтрЗаменить(СокрЛП(Поля[2]), ",", ".");
Количество = Число(КоличествоСтрокой);
// Поиск номенклатуры по артикулу и запись в таблицу
Строка = Чтение.ПрочитатьСтроку();
КонецЦикла;
Чтение.Закрыть();
КонецПроцедуры
Третий параметр СтрРазделить() равен Истина — пустые поля сохраняются. Иначе строка 123;;5 превратится в два элемента, и колонки съедут.
СтрРазделить() не понимает кавычки. Если в файле встречается "ООО ""Ромашка""; склад";10, точка с запятой внутри кавычек разрежет поле. Для таких файлов разбирайте строку посимвольно с флагом «внутри кавычек» или просите выгрузку с разделителем-табуляцией (Символы.Таб).
Перед Число() проверьте, что в поле нет пробелов-разделителей тысяч: "1 250,00" вызовет исключение. Уберите их через СтрЗаменить(Поле, " ", ""), а неразрывный пробел — через СтрЗаменить(Поле, Символы.НПП, "").
Кодировки и спецсимволы при чтении файла в 1С
Если вместо кириллицы на экране Привет или ромбики, файл прочитан не в той кодировке. Платформа не угадывает кодировку надёжно, поэтому указывайте её вторым параметром явно.
| Откуда файл | Кодировка | Как указать |
|---|---|---|
| Современные программы, веб-сервисы, Linux | UTF-8 | КодировкаТекста.UTF8 |
| Excel «CSV (разделители — запятые)», старые программы под Windows | Windows-1251 | "windows-1251" |
Программы под DOS, вывод консоли cmd | CP866 | КодировкаТекста.OEM или "cp866" |
| Блокнот Windows «Юникод» | UTF-16 | КодировкаТекста.UTF16 |
💡 Для кириллической кодировки Windows надёжнее строка "windows-1251", чем КодировкаТекста.ANSI. ANSI означает кодировку операционной системы, где выполняется код. На сервере 1С под Linux это будет не 1251, и та же обработка начнёт выдавать кракозябры.
Как быстро определить кодировку файла
- Откройте файл в Notepad++ или VS Code — кодировка видна в строке состояния.
- Если редактора нет, прочитайте первые строки в UTF-8. Видите
Р,Счерез букву — файл в 1251. Видите�— файл однобайтовый, а читаете как UTF-8. - Для автоматической загрузки договоритесь с источником о единой кодировке. Угадывание в коде — источник редких, но неприятных ошибок.
Невидимые символы, которые ломают разбор
- 🔹 BOM в начале файла. Если первая колонка заголовка не совпадает с ожидаемой, хотя выглядит так же, в начале строки может сидеть маркер порядка байтов. Уберите его:
СтрЗаменить(Строка, Символ(65279), ""). - 🔹 Перевод строки
ВК+ПС. Файлы из Windows заканчивают строку двумя символами. Если в конце значения осталсяСимволы.ВК, сравнениеПоле = "Да"не сработает. СпасаетСокрЛП(). - 🔹 Табуляция. Разделитель в выгрузках из учётных систем часто
Символы.Таб, а не;. Проверьте, прежде чем писать разбор. - 🔹 Неразрывный пробел (
Символы.НПП) в числах после копирования из Excel. Удаляйте его явно, не надеясь наСокрЛП().
Чтение файла целиком в одну строку
Когда файл небольшой и нужно всё его содержимое сразу (шаблон письма, JSON-настройки, короткий ответ сервиса), читайте его целиком.
Через ЧтениеТекста:
Чтение = Новый ЧтениеТекста(ИмяФайла, КодировкаТекста.UTF8);
Содержимое = Чтение.Прочитать();
Чтение.Закрыть();
Через ТекстовыйДокумент, если потом нужен доступ к строкам по номеру:
ТекстДок = Новый ТекстовыйДокумент;
ТекстДок.Прочитать(ИмяФайла, КодировкаТекста.UTF8);
Для НомерСтроки = 1 По ТекстДок.КоличествоСтрок() Цикл
Строка = ТекстДок.ПолучитьСтроку(НомерСтроки);
// обработка
КонецЦикла;
ВесьТекст = ТекстДок.ПолучитьТекст();
Строки в ТекстовыйДокумент нумеруются с 1, а не с 0.
Не читайте целиком файлы на сотни мегабайт: содержимое целиком ляжет в оперативную память рабочего процесса. На сервере с несколькими пользователями это ударит по всем. Для больших логов — только построчный обход.
Если строки нужны массивом
Частый приём — прочитать всё и сразу получить массив строк:
Строки = СтрРазделить(Содержимое, Символы.ПС, Истина);
Учтите, что в файлах Windows в конце каждого элемента останется Символы.ВК. Обрабатывайте строки через СокрЛП() или заранее замените Символы.ВК + Символы.ПС на Символы.ПС.
Как прочитать файл, выбранный пользователем на клиенте
Пользователь выбирает файл на своём компьютере, а разбирать его нужно на сервере: там справочники и запись документов. Передать файл можно через временное хранилище.
&НаКлиенте
Процедура ЗагрузитьИзФайла(Команда)
Оповещение = Новый ОписаниеОповещения("ПослеПомещенияФайла", ЭтотОбъект);
НачатьПомещениеФайла(Оповещение, , , Истина, УникальныйИдентификатор);
КонецПроцедуры
&НаКлиенте
Процедура ПослеПомещенияФайла(Результат, Адрес, ВыбранноеИмяФайла, ДополнительныеПараметры) Экспорт
Если Не Результат Тогда
Возврат; // пользователь отменил выбор
КонецЕсли;
ПрочитатьФайлНаСервере(Адрес);
КонецПроцедуры
&НаСервере
Процедура ПрочитатьФайлНаСервере(Адрес)
Данные = ПолучитьИзВременногоХранилища(Адрес);
Поток = Данные.ОткрытьПотокДляЧтения();
Чтение = Новый ЧтениеТекста(Поток, КодировкаТекста.UTF8);
Строка = Чтение.ПрочитатьСтроку();
Пока Строка <> Неопределено Цикл
// обработка строки
Строка = Чтение.ПрочитатьСтроку();
КонецЦикла;
Чтение.Закрыть();
Поток.Закрыть();
КонецПроцедуры
Асинхронный НачатьПомещениеФайла работает и в тонком, и в веб-клиенте. Синхронные диалоги в веб-клиенте запрещены, поэтому так надёжнее.
На платформах до 8.3.9, где нет потоков, двоичные данные записывают во временный файл и читают его:
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("txt");
Данные.Записать(ИмяВременногоФайла);
// чтение через ЧтениеТекста(ИмяВременногоФайла, ...)
УдалитьФайлы(ИмяВременногоФайла);
Если файл маленький, можно не открывать поток, а сразу получить текст: Текст = ПолучитьСтрокуИзДвоичныхДанных(Данные, КодировкаТекста.UTF8);.
Ошибки при чтении файла и как их перехватить
Чтение файла — внешняя операция. Файл могут удалить, переименовать или занять другой программой в любой момент. Код без обработки исключений упадёт с системным сообщением прямо у пользователя.
Функция ПрочитатьФайлБезопасно(ИмяФайла)
ФайлНаДиске = Новый Файл(ИмяФайла);
Если Не ФайлНаДиске.Существует() Тогда
Сообщить("Файл не найден: " + ИмяФайла);
Возврат Неопределено;
КонецЕсли;
Чтение = Неопределено;
Попытка
Чтение = Новый ЧтениеТекста(ИмяФайла, КодировкаТекста.UTF8);
Содержимое = Чтение.Прочитать();
Чтение.Закрыть();
Исключение
Если Чтение <> Неопределено Тогда
Чтение.Закрыть();
КонецЕсли;
ЗаписьЖурналаРегистрации("ЗагрузкаИзФайла",
УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
Сообщить("Не удалось прочитать файл: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
Возврат Неопределено;
КонецПопытки;
Возврат Содержимое;
КонецФункции
Подробности ошибки уходят в журнал регистрации, а пользователь видит короткое сообщение. Администратор потом найдёт запись по событию ЗагрузкаИзФайла в Администрирование → Обслуживание → Журнал регистрации.
Файл занят другой программой
Конструктор ЧтениеТекста по умолчанию открывает файл монопольно. Если внешняя программа в этот момент пишет в него лог, получите ошибку доступа. Для чтения таких файлов передайте пятым параметром Ложь:
Чтение = Новый ЧтениеТекста(ИмяФайла, КодировкаТекста.UTF8, , , Ложь);
Параметры по порядку: имя файла, кодировка, разделитель строк, конвертируемый разделитель строк, монопольный режим. Третий и четвёртый пропускаем — останутся значения по умолчанию.
Какой способ чтения выбрать под задачу
| Способ | Когда брать | Память | Ограничения |
|---|---|---|---|
ЧтениеТекста.ПрочитатьСтроку() | Логи, выгрузки, CSV любого размера | Одна строка | Только вперёд, назад вернуться нельзя |
ЧтениеТекста.Прочитать() | Небольшой файл целиком, JSON, шаблоны | Весь файл | Не для больших файлов |
ТекстовыйДокумент | Нужна строка по номеру, число строк, правка и сохранение | Весь файл | Медленнее на больших объёмах |
Поток из ДвоичныеДанные | Файл из временного хранилища, HTTP, вложения | Одна строка | Платформа 8.3.9 и новее |
ПолучитьСтрокуИзДвоичныхДанных() | Маленький файл, пришедший как двоичные данные | Весь файл | Платформа 8.3.9 и новее |
Короткое правило: не знаете размер файла — читайте построчно. Это всегда работает, разница в скорости на файлах до нескольких мегабайт незаметна.
Если файл нужно разобрать и сразу записать в базу, не создавайте документ на каждую строку внутри транзакции из тысячи записей. Накопите строки в ТаблицаЗначений, проверьте их и только потом пишите объекты. Так ошибка в 900-й строке не оставит в базе 899 наполовину загруженных документов.