Чтение CSV в 1С:Предприятии 8.3: табличный документ, текстовый поток и разбор полей

· 11 мин

Содержание

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

Частая ошибка — делить строку одной функцией СтрРазделить и считать дело сделанным. Первое же поле вида "ООО ""Ромашка""; склад 2" ломает разбор: точка с запятой внутри кавычек становится лишней колонкой, и весь хвост строки съезжает. Ниже — код, который это учитывает, и разбор кодировок, на которых спотыкаются чаще всего.

Что выяснить о CSV-файле до написания кода

CSV — это не стандартный формат, а договорённость. Один и тот же «прайс.csv» от двух поставщиков может отличаться по четырём параметрам. Откройте файл в Блокноте или Notepad++ (не в Excel) и запишите ответы.

ПараметрТипичные вариантыКак определить
Разделитель полей; (Excel в русской локали), ,, табуляцияПосмотреть первую строку
КодировкаUTF-8, UTF-8 с BOM, Windows-1251В Notepad++ — меню «Кодировки», внизу окна
Строка заголовковЕсть / нетПервая строка — названия колонок или данные
КавычкиТолько у полей с разделителем / у всех полейВидно по тексту

Ещё три вещи стоит проверить сразу:

  • 🔢 Формат чисел. 1 234,56 с неразрывным пробелом, 1234.56 или 1234,56 — от этого зависит функция преобразования.
  • 📅 Формат дат. 25.03.2025, 2025-03-25 или 25.03.2025 14:30:00.
  • ↩️ Переносы внутри полей. В выгрузках из CRM в поле «Комментарий» встречаются многострочные значения в кавычках. Если они есть, построчное чтение без доработки разорвёт запись пополам.

Попросите у источника данных 10–20 строк образца, где есть самые «грязные» случаи: кавычки, пустые значения, длинные комментарии. Отладка на таком файле экономит часы.

Способ 1. Чтение CSV через текстовый и табличный документ

Способ подходит для разовой загрузки и обработок с формой: пользователь видит данные в таблице, проверяет колонки и только потом нажимает «Загрузить». Файл целиком поднимается в память, поэтому для файлов до нескольких десятков тысяч строк это нормально, для миллиона строк — нет.

Метод ТабличныйДокумент.Прочитать() открывает форматы mxl, xls, xlsx, ods, но CSV как таблицу он не разбирает. Поэтому текст читаем через ТекстовыйДокумент, а ячейки заполняем сами:

&НаСервере
Функция CSVВТабличныйДокумент(ИмяФайла, Разделитель = ";")

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

    ТД = Новый ТабличныйДокумент;
    Для НомерСтроки = 1 По Текст.КоличествоСтрок() Цикл
        Поля = РазобратьСтрокуCSV(Текст.ПолучитьСтроку(НомерСтроки), Разделитель);
        Для Индекс = 0 По Поля.ВГраница() Цикл
            ТД.Область("R" + НомерСтроки + "C" + (Индекс + 1)).Текст = Поля[Индекс];
        КонецЦикла;
    КонецЦикла;

    Возврат ТД;

КонецФункции

Функция РазобратьСтрокуCSV приведена в разделе про разделители и кавычки. Готовый табличный документ выводите в поле формы и читайте обратно по адресам ячеек: ТД.Область("R2C3").Текст, границы — ТД.ВысотаТаблицы и ТД.ШиринаТаблицы.

Обходной путь через Excel

Если загрузка разовая и пишет её не программист, можно открыть CSV в Excel, сохранить как .xlsx и прочитать готовым методом:

ТД = Новый ТабличныйДокумент;
ТД.Прочитать(ИмяФайлаXLSX, СпособЧтенияЗначенийТабличногоДокумента.Текст);

Минус: Excel молча «чинит» данные. Артикул 00123 становится числом 123, код 1-2 — датой. Для регулярного обмена этот путь не годится.

Готовая загрузка в типовых конфигурациях

В конфигурациях на Библиотеке стандартных подсистем (Бухгалтерия 3.0, ЗУП 3, УТ 11) в списке номенклатуры и в табличных частях документов есть команда загрузки из файла. Она принимает табличные форматы, а в ряде релизов и CSV. Если нужно один раз залить прайс в номенклатуру, сначала проверьте эту команду — писать код может и не понадобиться.

Способ 2. Построчное чтение CSV текстовым потоком

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

Процедура ЗагрузитьCSV(ИмяФайла, Разделитель = ";", Кодировка = Неопределено) Экспорт

    Если Кодировка = Неопределено Тогда
        Кодировка = КодировкаТекста.UTF8;
    КонецЕсли;

    Чтение = Новый ЧтениеТекста(ИмяФайла, Кодировка);
    Заголовки = Неопределено;
    НомерСтроки = 0;

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

        НомерСтроки = НомерСтроки + 1;

        // Многострочное поле: нечётное число кавычек — запись не закончена
        Пока СтрЧислоВхождений(ТекСтрока, """") % 2 = 1 Цикл
            Продолжение = Чтение.ПрочитатьСтроку();
            Если Продолжение = Неопределено Тогда
                Прервать;
            КонецЕсли;
            ТекСтрока = ТекСтрока + Символы.ПС + Продолжение;
            НомерСтроки = НомерСтроки + 1;
        КонецЦикла;

        Если Не ПустаяСтрока(ТекСтрока) Тогда
            Поля = РазобратьСтрокуCSV(ТекСтрока, Разделитель);
            Если Заголовки = Неопределено Тогда
                Поля[0] = СтрЗаменить(Поля[0], Символ(65279), ""); // BOM
                Заголовки = Поля;
            Иначе
                ОбработатьЗапись(Заголовки, Поля, НомерСтроки);
            КонецЕсли;
        КонецЕсли;

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

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

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

ПрочитатьСтроку() возвращает Неопределено, когда файл закончился, — на этом держится цикл. Пустая строка в середине файла вернётся как "", поэтому её отдельно пропускаем.

Сравнение способов

СпособКогда братьОбъём файлаРиски
ТекстовыйДокумент + табличный документОбработка с предпросмотром, разовая загрузкаДо десятков тысяч строкРасход памяти, многострочные поля не склеиваются
ЧтениеТекста построчноРегулярный обмен, большие файлыБез практического ограниченияНужно самому писать разбор и проверки
Через Excel в .xlsxРазово, без программистаЛюбой, что откроет ExcelExcel искажает коды, нули, даты
Типовая команда загрузкиНоменклатура, табличные частиОбычные прайсыТолько под поддерживаемые объекты

Откуда берётся файл в управляемой форме

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

&НаКлиенте
Процедура ВыбратьФайл(Команда)
    Оповещение = Новый ОписаниеОповещения("ПослеПомещенияФайла", ЭтотОбъект);
    НачатьПомещениеФайла(Оповещение, , , Истина, УникальныйИдентификатор);
КонецПроцедуры

&НаКлиенте
Процедура ПослеПомещенияФайла(Результат, Адрес, ВыбранноеИмяФайла, ДополнительныеПараметры) Экспорт
    Если Результат Тогда
        ЗагрузитьНаСервере(Адрес);
    КонецЕсли;
КонецПроцедуры

&НаСервере
Процедура ЗагрузитьНаСервере(Адрес)
    ИмяФайла = ПолучитьИмяВременногоФайла("csv");
    ПолучитьИзВременногоХранилища(Адрес).Записать(ИмяФайла);
    ЗагрузитьCSV(ИмяФайла, ";");
    УдалитьФайлы(ИмяФайла);
КонецПроцедуры

Разделители, кавычки и многострочные поля в CSV

Правило CSV простое: поле, где есть разделитель, кавычка или перенос строки, заключается в кавычки. Кавычка внутри такого поля удваивается. Строка

"ООО ""Ромашка""; склад 2";1250,00;25.03.2025

содержит три поля: ООО "Ромашка"; склад 2, 1250,00 и 25.03.2025. СтрРазделить вернёт четыре — и с неверным содержимым. Функция ниже идёт по строке посимвольно и помнит, находится ли она внутри кавычек:

Функция РазобратьСтрокуCSV(ТекСтрока, Разделитель = ";") Экспорт

    Поля = Новый Массив;
    Значение = "";
    ВКавычках = Ложь;
    Длина = СтрДлина(ТекСтрока);
    Позиция = 1;

    Пока Позиция <= Длина Цикл
        Знак = Сред(ТекСтрока, Позиция, 1);
        Если ВКавычках Тогда
            Если Знак = """" Тогда
                Если Сред(ТекСтрока, Позиция + 1, 1) = """" Тогда
                    Значение = Значение + """"; // удвоенная кавычка
                    Позиция = Позиция + 1;
                Иначе
                    ВКавычках = Ложь;
                КонецЕсли;
            Иначе
                Значение = Значение + Знак;
            КонецЕсли;
        Иначе
            Если Знак = """" Тогда
                ВКавычках = Истина;
            ИначеЕсли Знак = Разделитель Тогда
                Поля.Добавить(Значение);
                Значение = "";
            Иначе
                Значение = Значение + Знак;
            КонецЕсли;
        КонецЕсли;
        Позиция = Позиция + 1;
    КонецЦикла;

    Поля.Добавить(Значение);
    Возврат Поля;

КонецФункции

Если вы точно знаете, что кавычек в файле нет (например, выгрузка вашей же системы), берите СтрРазделить(ТекСтрока, ";", Истина). Третий параметр Истина сохраняет пустые поля — без него a;;c превратится в два значения вместо трёх, и колонки съедут.

Автоопределение разделителя

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

Функция ОпределитьРазделитель(СтрокаЗаголовков)
    Варианты = Новый Массив;
    Варианты.Добавить(";");
    Варианты.Добавить(",");
    Варианты.Добавить(Символы.Таб);
    Лучший = ";";
    Максимум = 0;
    Для Каждого Вариант Из Варианты Цикл
        Количество = СтрЧислоВхождений(СтрокаЗаголовков, Вариант);
        Если Количество > Максимум Тогда
            Максимум = Количество;
            Лучший = Вариант;
        КонецЕсли;
    КонецЦикла;
    Возврат Лучший;
КонецФункции

Запятая как разделитель конфликтует с русскими дробными числами 1250,50. В корректном файле такие числа стоят в кавычках. Если кавычек нет — файл неразбираем однозначно, просите источник сменить разделитель на ;.

Проверка данных и обработка ошибок при загрузке CSV

Строка CSV — это набор строк, не чисел и не дат. Каждое поле нужно привести к типу и при неудаче не падать, а запомнить ошибку с номером строки.

Числа и даты

Функция СтрокаВЧисло(Значение, Результат)
    Чистая = СокрЛП(Значение);
    Чистая = СтрЗаменить(Чистая, " ", "");
    Чистая = СтрЗаменить(Чистая, Символы.НПП, ""); // неразрывный пробел из Excel
    Чистая = СтрЗаменить(Чистая, ",", ".");
    Если Чистая = "" Тогда
        Результат = 0;
        Возврат Истина;
    КонецЕсли;
    Попытка
        Результат = Число(Чистая);
        Возврат Истина;
    Исключение
        Возврат Ложь;
    КонецПопытки;
КонецФункции

Функция СтрокаВДату(Значение, Результат)
    Части = СтрРазделить(Лев(СокрЛП(Значение), 10), ".-/");
    Если Части.Количество() <> 3 Тогда
        Возврат Ложь;
    КонецЕсли;
    Попытка
        Если СтрДлина(Части[0]) = 4 Тогда // 2025-03-25
            Результат = Дата(Число(Части[0]), Число(Части[1]), Число(Части[2]));
        Иначе                              // 25.03.2025
            Результат = Дата(Число(Части[2]), Число(Части[1]), Число(Части[0]));
        КонецЕсли;
        Возврат Истина;
    Исключение
        Возврат Ложь;
    КонецПопытки;
КонецФункции

Второй параметр СтрРазделить — набор символов-разделителей, поэтому ".-/" делит и по точке, и по дефису, и по косой черте.

Журнал ошибок вместо падения

Заведите таблицу значений с колонками «Строка», «Поле», «Значение», «Ошибка». В ОбработатьЗапись при каждой неудаче добавляйте туда строку и переходите к следующей записи. После загрузки покажите пользователю итог: «Загружено 4 812, ошибок 17» и сами ошибки.

Что стоит проверять, кроме типов:

  • 📋 Число полей. Если в строке меньше колонок, чем в заголовке, — почти наверняка сломан разбор или в файле лишний перенос.
  • 🔑 Обязательные поля. Пустой артикул или ИНН — запись пропускаем.
  • 🔍 Поиск ссылок. Номенклатуру, контрагентов ищите по коду или ИНН одним запросом на всю пачку, а не НайтиПоРеквизиту в цикле по каждой строке.
  • ♻️ Повторная загрузка. Решите заранее, что делать с уже существующим элементом: обновить или пропустить.

Для регламентной загрузки, где пользователя нет, пишите итог в журнал регистрации:

ЗаписьЖурналаРегистрации("Обмен.ЗагрузкаCSV",
    УровеньЖурналаРегистрации.Ошибка, , ,
    "Строка " + НомерСтроки + ": " + ТекстОшибки);

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

Большие файлы записывайте порциями по 500–1000 объектов в транзакции. Одна транзакция на весь файл держит блокировки долго и при ошибке в последней строке откатывает всё.

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

Кодировки, BOM и спецсимволы в CSV

Кодировка — главный источник проблем при чтении CSV в 1С. Платформа не угадывает её сама: что передали в конструктор, то и применит.

Источник файлаОбычная кодировкаЧто указать
Excel, «CSV (разделители — запятые)»Windows-1251"windows-1251"
Excel, «CSV UTF-8»UTF-8 с BOMКодировкаТекста.UTF8
Выгрузки веб-сервисов, Python, PHPUTF-8 без BOMКодировкаТекста.UTF8
Старые DOS-программыCP866КодировкаТекста.OEM

Если источник неизвестен, помогает простая проверка: прочитайте файл как UTF-8 и поищите символ замены с кодом 65533. Он появляется, когда байты не складываются в корректный UTF-8:

Текст = Новый ТекстовыйДокумент;
Текст.Прочитать(ИмяФайла, КодировкаТекста.UTF8);
Если СтрНайти(Текст.ПолучитьТекст(), Символ(65533)) > 0 Тогда
    Кодировка = "windows-1251";
Иначе
    Кодировка = КодировкаТекста.UTF8;
КонецЕсли;

Для больших файлов проверяйте не весь текст, а первые 100–200 строк.

Спецсимволы, которые стоит чистить в каждом поле:

  • ⎵ Неразрывный пробел (Символы.НПП) — Excel вставляет его в числа и ФИО. СокрЛП его не убирает.
  • 🧩 BOM (Символ(65279)) — только в начале файла, прилипает к первому заголовку.
  • ↵ Возврат каретки (Символы.ВК) — может остаться в конце последнего поля, если файл с переносами Windows разбирали как Unix. Проверка Поле = "Да" при этом не срабатывает.
  • ⇥ Табуляция внутри текстовых полей в файлах с разделителем ; — безвредна, но мешает поиску по точному совпадению.

Загрузка CSV по расписанию

Когда поставщик раз в день кладёт файл в общую папку, загрузку переводят на регламентное задание.

  1. В Конфигураторе создайте общий модуль с флажком «Сервер» и экспортной процедурой без параметров, например ЗагрузкаCSVПоРасписанию().
  2. В ветке Общие → Регламентные задания добавьте задание, в поле «Имя метода» укажите эту процедуру.
  3. Задайте расписание и включите флажок «Использование». Флажок «Предопределенное» создаст задание в базе автоматически.
  4. Обновите конфигурацию базы. В конфигурациях на БСП расписание потом меняется без Конфигуратора: Администрирование → Обслуживание → Регламентные операции → Регламентные и фоновые задания.

Сама процедура обходит папку и переносит обработанные файлы, чтобы не загрузить их дважды:

Процедура ЗагрузкаCSVПоРасписанию() Экспорт
    Каталог = "\\fileserver\obmen\in\";
    Для Каждого Файл Из НайтиФайлы(Каталог, "*.csv") Цикл
        Попытка
            ЗагрузитьCSV(Файл.ПолноеИмя, ";");
            ПереместитьФайл(Файл.ПолноеИмя, Каталог + "done\" + Файл.Имя);
        Исключение
            ЗаписьЖурналаРегистрации("Обмен.ЗагрузкаCSV",
                УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
            ПереместитьФайл(Файл.ПолноеИмя, Каталог + "error\" + Файл.Имя);
        КонецПопытки;
    КонецЦикла;
КонецПроцедуры

Тонкие места регламентной загрузки:

  • 🖥️ Права на папку. В клиент-серверной базе код выполняется на сервере 1С от имени пользователя, под которым работает служба (часто USR1CV8). Пути вида Z:\ там не существуют — указывайте UNC-путь \\сервер\папка и дайте этому пользователю права на чтение и запись.
  • 📂 Файловая база. Регламентные задания в файловом варианте выполняются, только пока с базой работает хотя бы один сеанс. Ночью при выключенных компьютерах загрузки не будет.
  • ⏳ Недописанный файл. Если источник ещё пишет файл, а задание уже читает, загрузится половина. Договоритесь, что источник пишет во временное имя .tmp и переименовывает в .csv в конце.
  • 🚫 Никаких диалогов. В регламентном задании нет пользователя: Сообщить, Вопрос и выбор файла не сработают. Все сообщения — в журнал регистрации.

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

Как выгрузить данные из 1С обратно в CSV?
Через ЗаписьТекста: собирайте строку из полей через ;, поля с разделителем, кавычкой или переносом берите в кавычки, а кавычки внутри удваивайте. Для Excel в русской локали удобнее кодировка "windows-1251".
Почему после Excel пропали ведущие нули в ИНН и артикулах?
Excel при открытии CSV сам превращает похожие на числа значения в числа. Не открывайте и не пересохраняйте файл в Excel перед загрузкой, а при чтении в 1С храните коды как строки.
Работает ли чтение CSV в веб-клиенте?
Да. Файл передаётся на сервер через НачатьПомещениеФайла и временное хранилище, а разбор идёт на сервере. Код чтения от клиента не зависит.
Как прочитать CSV с разделителем-табуляцией?
Передайте в функцию разбора Символы.Таб вместо ";". Такие файлы часто имеют расширение .tsv или .txt, но читаются так же.
Сколько строк можно загрузить за раз?
При построчном чтении через ЧтениеТекста ограничение задаёт не файл, а время записи объектов. Сотни тысяч строк — рабочий объём, если писать порциями по транзакциям и искать ссылки запросом на пачку.