Чтение txt, csv и логов во встроенном языке 1С 8.3

· 9 мин

Содержание

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

Типичная ситуация: банк прислал выписку в CSV, склад выгрузил остатки в txt, а внешняя программа пишет лог, который надо разобрать обработкой. Ниже код для каждого случая, разбор кодировок и обработка ошибок. Всё относится к платформе 1С:Предприятие 8.3 и не зависит от конфигурации: код работает в БП, ЗУП, УТ и любой своей обработке.

Какие объекты платформы читают текстовые файлы

В платформе 8.3 есть три основных инструмента. Они отличаются тем, сколько памяти тратят и что умеют.

  • 📄 ЧтениеТекста — последовательное чтение файла или потока. Держит в памяти только текущую строку. Подходит для файлов любого размера.
  • 📝 ТекстовыйДокумент — загружает весь файл и даёт доступ к строке по номеру: ПолучитьСтроку(Номер), КоличествоСтрок(). Удобен, когда нужно вернуться назад или знать число строк заранее.
  • 🔀 Потоки и двоичные данные — ДвоичныеДанные, ОткрытьПотокДляЧтения(), функция ПолучитьСтрокуИзДвоичныхДанных(). Нужны, когда файл пришёл не с диска сервера, а из временного хранилища, HTTP-ответа или вложения. Появились в 8.3.9.

Есть ещё объект Файл. Он сам ничего не читает, но проверяет, существует ли файл, и даёт его размер и имя. Его удобно вызывать перед чтением.

Где выполняется код, там и ищется файл. Путь C:\Обмен\остатки.txt в серверной процедуре ищется на сервере 1С, а не на компьютере бухгалтера. С этого и начинайте разбор ошибки «файл не найден».

Построчное чтение текстового файла: базовый алгоритм

Построчный обход — основной способ. Он не зависит от размера файла: лог на 2 ГБ читается так же, как файл на 10 строк.

Процедура ПрочитатьФайлПострочно(ИмяФайла)

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

    НомерСтроки = 0;
    Строка = Чтение.ПрочитатьСтроку();

    Пока Строка <> Неопределено Цикл
        НомерСтроки = НомерСтроки + 1;

        // Здесь обработка строки
        Сообщить(СтрШаблон("%1: %2", НомерСтроки, Строка));

        Строка = Чтение.ПрочитатьСтроку();
    КонецЦикла;

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

КонецПроцедуры

Что здесь важно:

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

Отбор нужных строк из лога

Из лога обычно нужны не все строки, а только ошибки. Фильтр ставится внутри того же цикла:

Если СтрНайти(ВРег(Строка), "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С

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

Откуда файлКодировкаКак указать
Современные программы, веб-сервисы, LinuxUTF-8КодировкаТекста.UTF8
Excel «CSV (разделители — запятые)», старые программы под WindowsWindows-1251"windows-1251"
Программы под DOS, вывод консоли cmdCP866КодировкаТекста.OEM или "cp866"
Блокнот Windows «Юникод»UTF-16КодировкаТекста.UTF16

💡 Для кириллической кодировки Windows надёжнее строка "windows-1251", чем КодировкаТекста.ANSI. ANSI означает кодировку операционной системы, где выполняется код. На сервере 1С под Linux это будет не 1251, и та же обработка начнёт выдавать кракозябры.

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

  1. Откройте файл в Notepad++ или VS Code — кодировка видна в строке состояния.
  2. Если редактора нет, прочитайте первые строки в UTF-8. Видите Р, С через букву — файл в 1251. Видите � — файл однобайтовый, а читаете как UTF-8.
  3. Для автоматической загрузки договоритесь с источником о единой кодировке. Угадывание в коде — источник редких, но неприятных ошибок.

Невидимые символы, которые ломают разбор

  • 🔹 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 наполовину загруженных документов.

Частые вопросы о чтении текстовых файлов

Можно ли прочитать файл с компьютера пользователя без диалога выбора?
В тонком клиенте можно передать путь в НачатьПомещениеФайла с параметром Интерактивно = Ложь. В веб-клиенте браузер такое запрещает: пользователь должен выбрать файл сам.
Как прочитать только первые N строк большого файла?
Используйте построчный цикл со счётчиком и выйдите из него через Прервать, когда счётчик достигнет N. Не забудьте вызвать Закрыть() после цикла.
Чем читать Excel-файл, если в нём кириллица и формулы?
Объекты чтения текста подходят только для txt и csv. Файл xlsx — это архив, его читают через ТабличныйДокумент.Прочитать() или сохраняют из Excel в CSV.
Как прочитать JSON из текстового файла?
Для JSON есть отдельный объект ЧтениеJSON с методом ОткрытьФайл(). Он сам разбирает структуру, вручную делить строки не нужно.
Почему последняя строка файла не обрабатывается?
Обычно второе чтение стоит в начале тела цикла, а не в конце, и последнюю строку перетирает Неопределено. Проверьте порядок: обработка, затем ПрочитатьСтроку().