Чтение CSV-файла в 1С 8.3: от кодировки до таблицы значений
Содержание
CSV в 1С читают как обычный текст: открывают файл объектом ЧтениеТекста, берут строки по одной, режут каждую по разделителю функцией СтрРазделить и складывают результат в ТаблицуЗначений. Специального объекта «ЧитательCSV» в платформе нет, и это нормально: формат простой, всё решают три вещи — кодировка, разделитель и кавычки.
Если файл пришёл из Excel, чаще всего это windows-1251 и разделитель ;. Если из выгрузки интернет-магазина или скрипта — UTF-8 и запятая. Ошибиться с кодировкой — получить «кракозябры» в первой же колонке, ошибиться с разделителем — получить одну длинную колонку вместо десяти.
Что проверить в файле до начала загрузки
Откройте файл в любом текстовом редакторе, а не в Excel. Excel «исправляет» файл на лету: срезает ведущие нули в артикулах, превращает 1-2 в дату, а длинные штрихкоды в 4,6E+12. Увидеть реальное содержимое можно только в редакторе.
Что смотреть:
- 🔤 Кодировка. Русские буквы читаются нормально — значит, редактор угадал верно; сомневаетесь — переключите кодировку вручную и посмотрите, что изменится.
- ✂️ Разделитель. Точка с запятой, запятая, табуляция или вертикальная черта. Русский Excel по умолчанию сохраняет с
;, потому что запятая у нас десятичная. - 📌 Строка заголовков. Есть ли она, и совпадают ли названия колонок с тем, что вы ждёте.
- 💬 Кавычки. Встречаются ли значения вида
"ООО ""Ромашка"", Москва"— с разделителем и кавычками внутри поля. - 🔢 Формат чисел и дат.
1 234,56или1234.56;15.01.2026или2026-01-15. - 📏 Размер. До нескольких мегабайт хватит простого кода, от десятков мегабайт нужны приёмы из раздела про производительность.
Если у вас есть BOM — три служебных байта в начале файла UTF-8, — в редакторе его не видно, зато в 1С первая колонка может получить «невидимый» символ в начале имени. Ниже есть, как от этого защититься.
Как задать кодировку при чтении
Кодировка указывается вторым параметром конструктора ЧтениеТекста. Без неё платформа применит кодировку по умолчанию, и русский текст из файла в другой кодировке превратится в мусор.
Чтение = Новый ЧтениеТекста(ПутьКФайлу, КодировкаТекста.UTF8);
Для файла из русского Excel подставьте КодировкаТекста.ANSI — на русскоязычной системе это windows-1251. Можно передать и имя строкой: "windows-1251", "utf-8".
Автоопределения кодировки в платформе нет. Практичный приём — читать первую строку и проверять результат:
Функция КодировкаПодходит(ПутьКФайлу, Кодировка)
Чтение = Новый ЧтениеТекста(ПутьКФайлу, Кодировка);
Строка = Чтение.ПрочитатьСтроку();
Чтение.Закрыть();
Возврат Строка <> Неопределено И СтрНайти(Строка, "�") = 0;
КонецФункции
Символ � (знак замены) появляется, когда UTF-8 прочитали неверно. Для обратной ситуации — windows-1251, прочитанная как UTF-8, — обычно виден тот же знак. Если проверка не прошла для UTF8, пробуйте ANSI.
Для файла, который вам присылают регулярно, не гадайте в коде: договоритесь с отправителем об одной кодировке и зафиксируйте её. Автоподбор нужен только для файлов от случайных людей.
Откуда взять файл
На клиенте путь обычно выбирают через диалог выбора файла. На сервере файла по пути пользователя нет: данные нужно передать с клиента как ДвоичныеДанные или во временное хранилище, а на сервере записать во временный файл:
ИмяВремФайла = ПолучитьИмяВременногоФайла("csv");
ДвоичныеДанные.Записать(ИмяВремФайла);
// ... чтение ...
УдалитьФайлы(ИмяВремФайла);
Временный файл удаляйте всегда, в том числе при ошибке — используйте Попытка … Исключение.
Построчное чтение: рабочий каркас
Основной способ — читать файл строка за строкой. Память не растёт вместе с размером файла, потому что в каждый момент в ней одна строка.
Функция ПрочитатьCSV(ПутьКФайлу, Кодировка = Неопределено, Разделитель = ";")
Таблица = Новый ТаблицаЗначений;
Если Кодировка = Неопределено Тогда
Кодировка = КодировкаТекста.UTF8;
КонецЕсли;
Чтение = Новый ЧтениеТекста(ПутьКФайлу, Кодировка);
Попытка
Заголовок = Чтение.ПрочитатьСтроку();
Если Заголовок = Неопределено Тогда
Чтение.Закрыть();
Возврат Таблица;
КонецЕсли;
// Убираем BOM, если он остался в первой строке
Если Лев(Заголовок, 1) = Символ(65279) Тогда
Заголовок = Сред(Заголовок, 2);
КонецЕсли;
Для Каждого Имя Из РазобратьСтрокуCSV(Заголовок, Разделитель) Цикл
Таблица.Колонки.Добавить("К" + Формат(Таблица.Колонки.Количество() + 1, "ЧГ="), , Имя);
КонецЦикла;
Строка = Чтение.ПрочитатьСтроку();
Пока Строка <> Неопределено Цикл
Если НЕ ПустаяСтрока(Строка) Тогда
Поля = РазобратьСтрокуCSV(Строка, Разделитель);
НоваяСтрока = Таблица.Добавить();
Для Индекс = 0 По Мин(Поля.ВГраница(), Таблица.Колонки.Количество() - 1) Цикл
НоваяСтрока[Индекс] = Поля[Индекс];
КонецЦикла;
КонецЕсли;
Строка = Чтение.ПрочитатьСтроку();
КонецЦикла;
Исключение
Чтение.Закрыть();
ВызватьИсключение;
КонецПопытки;
Чтение.Закрыть();
Возврат Таблица;
КонецФункции
Колонки называются К1, К2… — настоящие названия из заголовка попадают в синоним. Так проще: в именах колонок нельзя использовать пробелы и многие символы, а в заголовках CSV они встречаются постоянно.
Закрывайте файл всегда. Незакрытый ЧтениеТекста держит файл открытым, и следующая попытка перезаписать или удалить его завершится ошибкой доступа.
А что с ТабличнымДокументом
ТабличныйДокумент читает файлы своих форматов: mxl, Excel, OpenDocument. Прочитать через него «обычный» CSV надёжно нельзя, и расчёт на это — частая ловушка. Если файл нужен в виде таблицы на экране, сначала загрузите данные в ТаблицуЗначений, а потом выведите её в табличный документ циклом по строкам.
Есть и обратный путь: открыть CSV в Excel, пересохранить как .xlsx и читать уже ТабличныйДокумент — но это ручной шаг, для автоматического обмена он не годится.
Разделители, кавычки и переносы строк
Простой СтрРазделить(Строка, ";", Ложь) работает, пока в данных нет самого разделителя. Как только в названии контрагента появилась запятая или точка с запятой, формат прячет такое поле в кавычки, а внутри кавычек заменяет " на "".
Пример строки:
1001;"ООО ""Ромашка""; филиал";15.01.2026;1 234,56
Здесь четыре поля, но СтрРазделить по ; даст пять. Нужен разбор с учётом кавычек:
Функция РазобратьСтрокуCSV(Строка, Разделитель = ";")
Результат = Новый Массив;
Поле = "";
ВКавычках = Ложь;
Длина = СтрДлина(Строка);
Позиция = 1;
Пока Позиция <= Длина Цикл
Символ = Сред(Строка, Позиция, 1);
Если ВКавычках Тогда
Если Символ = """" Тогда
Если Сред(Строка, Позиция + 1, 1) = """" Тогда
Поле = Поле + """";
Позиция = Позиция + 1;
Иначе
ВКавычках = Ложь;
КонецЕсли;
Иначе
Поле = Поле + Символ;
КонецЕсли;
ИначеЕсли Символ = """" Тогда
ВКавычках = Истина;
ИначеЕсли Символ = Разделитель Тогда
Результат.Добавить(Поле);
Поле = "";
Иначе
Поле = Поле + Символ;
КонецЕсли;
Позиция = Позиция + 1;
КонецЦикла;
Результат.Добавить(Поле);
Возврат Результат;
КонецФункции
Функция идёт по символам и помнит, внутри кавычек она сейчас или нет. Удвоенная кавычка внутри поля превращается в одну.
Что ещё встречается:
| Ситуация | Как выглядит | Что делать |
|---|---|---|
Табуляция вместо ; | Файл .tsv или .txt | Передать Символы.Таб как разделитель |
| Перенос строки внутри поля | Запись «ломается» на две строки | Склеивать строки, пока число кавычек нечётное |
| Лишние пробелы вокруг значений | " 1001 " | Применить СокрЛП к каждому полю |
| Разное число полей в строках | Строка короче заголовка | Дополнять пустыми значениями, как в каркасе выше |
| Строка итогов в конце файла | «Итого;;;5000» | Отбрасывать по признаку первой колонки |
Перенос строки внутри кавычек — самая коварная проблема. Построчное чтение разрежет такую запись на две строки, и разбор покажет мусор. Если такие файлы вам встречаются, накапливайте строки в буфере, пока количество символов " не станет чётным, и только потом разбирайте запись целиком.
Приведение значений к нужным типам
После разбора все поля — строки. Чтобы сравнивать, суммировать и записывать в реквизиты документов, значения нужно привести к числам, датам и ссылкам.
Числа
Формат 1 234,56 с пробелом-разделителем тысяч и запятой напрямую в число не превращается надёжно: поведение зависит от настроек системы. Нормализуйте строку сами:
Функция СтрокаВЧисло(Значение)
Текст = СтрЗаменить(СтрЗаменить(СтрЗаменить(Значение, " ", ""), Символ(160), ""), ",", ".");
Если ПустаяСтрока(Текст) Тогда
Возврат 0;
КонецЕсли;
Описание = Новый ОписаниеТипов("Число");
Возврат Описание.ПривестиЗначение(Текст);
КонецФункции
Символ с кодом 160 — неразрывный пробел, он часто прячется в числах, выгруженных из Excel и сайтов. Обычный пробел с ним не совпадает, поэтому убираем оба.
Для строки, которую невозможно распознать, ПривестиЗначение вернёт 0 — молча. Если нужно ловить ошибки, проверяйте строку на допустимые символы заранее и считайте отказы.
Даты
Формат 15.01.2026 разбираем по частям — так результат не зависит от региональных настроек:
Функция СтрокаВДату(Значение)
Части = СтрРазделить(СокрЛП(Значение), ".");
Если Части.Количество() <> 3 Тогда
Возврат Дата(1, 1, 1);
КонецЕсли;
Возврат Дата(Число(Части[2]), Число(Части[1]), Число(Части[0]));
КонецФункции
Для формата 2026-01-15 разделитель другой, а порядок частей обратный: год, месяц, день. Не пытайтесь угадывать формат по одной строке — задайте его явно параметром.
Ссылки и справочники
Артикул или ИНН из CSV превращают в ссылку запросом или методом НайтиПоКоду. Делать это в цикле по каждой строке медленно — подробнее в следующем разделе.
Ещё две ловушки:
- ИНН и артикулы с ведущими нулями (
0012345) должны остаться строками. Если файл уже побывал в Excel, нули могли пропасть до того, как он попал к вам, — вернуть их можно только дополнением до нужной длины, и то если длина известна. - Пустое поле — это не ноль. Отличайте «нет данных» от «значение 0», если для вас это разные вещи.
Большие файлы: как не ждать часами
На файле в 100 тысяч строк обычный код с обращением к базе внутри цикла может работать десятки минут. Основные потери — не в чтении, а в том, что происходит с каждой строкой.
Что реально ускоряет:
- Не обращайтесь к базе в цикле. Соберите все уникальные артикулы или ИНН в массив, одним запросом получите соответствие «ключ → ссылка» и храните его в
Соответствие. Поиск поСоответствиюв памяти на порядки быстрее запроса на каждую строку. - Складывайте в таблицу значений, а не в документы. Сначала загрузка и проверка, потом — пакетная запись.
- Выполняйте загрузку на сервере. Каждый вызов клиент-сервер стоит времени; весь цикл должен идти в одной серверной процедуре.
- Выносите длинную загрузку в фоновое задание, чтобы пользователь не смотрел на зависший интерфейс, и показывайте прогресс.
- Записывайте порциями — например, по 1000 объектов в транзакции, а не всё одной огромной транзакцией и не по одной записи.
- Отключайте лишнее. Для технической загрузки справочников используйте
ОбменДанными.Загрузка = Истина, если логика проведения вам не нужна, — но только если понимаете, какие проверки и регистрации обхода это отключает.
Запись порциями и отключение проверок — это вмешательство в учёт. Перед массовой загрузкой сделайте копию базы и прогоните файл на тестовой базе: ошибочный файл на 50 тысяч строк в рабочей базе потом придётся откатывать.
Если строк миллионы, разумнее вообще не тащить файл в 1С целиком: разрежьте на части внешним скриптом или используйте внешний источник данных. Чтение всего файла одним вызовом Прочитать() в одну строку при этом есть смысл применять только для небольших файлов — оно загружает в память весь текст целиком.
Разбор типичных сбоев при чтении
КодировкаТекста.UTF8 вторым параметром ЧтениеТекста.windows-1251 прочитан как UTF-8. Используйте КодировкаТекста.ANSI.; там запятая или табуляция. Откройте файл в редакторе и проверьте.Закрыть() и в ветке ошибки тоже.Частые вопросы
Можно ли прочитать CSV без программирования, штатными средствами?
.xlsx.Как узнать, сколько строк в файле, не читая его целиком?
Как загрузить файл, где заголовка нет?
Чем `ЧтениеТекста` отличается от `ТекстовыйДокумент`?
ЧтениеТекста читает последовательно и не держит файл в памяти. ТекстовыйДокумент загружает весь файл целиком, зато даёт доступ к строкам по номеру. Для больших CSV берите ЧтениеТекста.Как читать CSV, лежащий на веб-сервере, не сохраняя на диск?
ДвоичныеДанные и откройте поток на них; ЧтениеТекста умеет работать с потоком, а не только с именем файла.