Чтение файлов с диска во встроенном языке 1С 8.3
Содержание
Чтобы прочитать файл в 1С, для текста (txt, csv, log) берут объект ЧтениеТекста и читают построчно методом ПрочитатьСтроку(). Для XML — ЧтениеXML или ПостроительDOM. Для любых других форматов — ДвоичныеДанные и потоки (ФайловыйПоток, ЧтениеДанных). Способ выбирают по размеру и формату: маленький txt можно загрузить целиком, файл на сотни мегабайт читают только потоком.
Всё ниже относится к платформе 1С:Предприятие 8.3 и не зависит от конфигурации: код одинаково работает во внешней обработке, расширении или общем модуле БП, ЗУП и УТ. Отличается только место, где код выполняется, — на клиенте или на сервере. От этого зависит, какой диск «видит» программа.
Как прочитать текстовый файл в 1С построчно и целиком
Для текстовых файлов у платформы два инструмента. Они решают одну задачу, но по-разному расходуют память.
| Объект | Как читает | Когда брать |
|---|---|---|
ЧтениеТекста | построчно, потоком | файлы любого размера, логи, выгрузки |
ТекстовыйДокумент | загружает файл в память целиком | небольшие файлы, нужен доступ к строке по номеру |
Построчное чтение через ЧтениеТекста
Это основной способ. В памяти держится одна строка, поэтому файл на 500 МБ читается так же спокойно, как на 5 КБ.
ИмяФайла = "C:\Обмен\prices.txt";
Чтение = Новый ЧтениеТекста(ИмяФайла, КодировкаТекста.UTF8);
Строка = Чтение.ПрочитатьСтроку();
Пока Строка <> Неопределено Цикл
// обработка строки
Сообщить(Строка);
Строка = Чтение.ПрочитатьСтроку();
КонецЦикла;
Чтение.Закрыть();
Как работает цикл:
- Конструктор открывает файл в указанной кодировке.
ПрочитатьСтроку()возвращает очередную строку без символа перевода.- Когда строки кончились, метод возвращает
Неопределено— это и есть признак конца файла. Закрыть()освобождает файл. Без него другой процесс не сможет его удалить или перезаписать.
Пустая строка в файле приходит как "", а не как Неопределено. Поэтому проверка Пока Строка <> "" оборвёт чтение на первой пустой строке. Сравнивайте именно с Неопределено.
Если нужен весь текст одной строкой, вызовите Чтение.Прочитать() без параметров. Удобно для небольших файлов, которые потом передают в СтрРазделить или регулярную обработку.
Загрузка целиком через ТекстовыйДокумент
Текст = Новый ТекстовыйДокумент;
Текст.Прочитать(ИмяФайла, КодировкаТекста.UTF8);
Для НомерСтроки = 1 По Текст.КоличествоСтрок() Цикл
Строка = Текст.ПолучитьСтроку(НомерСтроки);
// обработка
КонецЦикла;
Нумерация строк здесь начинается с единицы. Плюс подхода — можно сразу узнать число строк и показать прогресс. Минус — весь файл лежит в памяти, а на клиенте синхронный Прочитать может блокировать интерфейс. В клиентском коде под веб-клиент используют асинхронные варианты.
Разбор CSV и табличных файлов в 1С
Отдельного встроенного объекта для CSV в платформе нет. CSV — это текст, поэтому его читают через ЧтениеТекста, а каждую строку делят на поля.
Простой случай: поля без кавычек
Если в значениях нет разделителя и кавычек, хватает функции СтрРазделить:
Чтение = Новый ЧтениеТекста(ИмяФайла, КодировкаТекста.ANSI);
Заголовок = Чтение.ПрочитатьСтроку(); // первая строка — имена колонок
Строка = Чтение.ПрочитатьСтроку();
Пока Строка <> Неопределено Цикл
Поля = СтрРазделить(Строка, ";", Истина);
Если Поля.Количество() >= 3 Тогда
Артикул = СокрЛП(Поля[0]);
Наименование = СокрЛП(Поля[1]);
Цена = ЧислоИзСтроки(Поля[2]);
КонецЕсли;
Строка = Чтение.ПрочитатьСтроку();
КонецЦикла;
Чтение.Закрыть();
Третий параметр Истина у СтрРазделить сохраняет пустые поля. Без него строка А;;100 даст два элемента вместо трёх, и колонки съедут.
Поля в кавычках
Excel и большинство выгрузок берут значение в кавычки, если внутри есть разделитель: "ООО ""Ромашка""; склад";150. СтрРазделить такую строку разрежет неправильно. Нужен разбор посимвольно:
Функция РазобратьСтрокуCSV(Строка, Разделитель = ";")
Поля = Новый Массив;
Поле = "";
ВКавычках = Ложь;
Длина = СтрДлина(Строка);
Сч = 1;
Пока Сч <= Длина Цикл
Символ = Сред(Строка, Сч, 1);
Если ВКавычках Тогда
Если Символ = """" Тогда
Если Сред(Строка, Сч + 1, 1) = """" Тогда
Поле = Поле + """"; // удвоенная кавычка внутри значения
Сч = Сч + 1;
Иначе
ВКавычках = Ложь;
КонецЕсли;
Иначе
Поле = Поле + Символ;
КонецЕсли;
ИначеЕсли Символ = """" Тогда
ВКавычках = Истина;
ИначеЕсли Символ = Разделитель Тогда
Поля.Добавить(Поле);
Поле = "";
Иначе
Поле = Поле + Символ;
КонецЕсли;
Сч = Сч + 1;
КонецЦикла;
Поля.Добавить(Поле);
Возврат Поля;
КонецФункции
Для строки из примера функция вернёт два поля: ООО "Ромашка"; склад и 150. Ограничение одно: перенос строки внутри кавычек она не склеит. Если такие значения встречаются, накапливайте строку, пока число кавычек в ней нечётное.
Числа и даты из CSV
Числа в выгрузках приходят с запятой и пробелами-разделителями тысяч: 1 250,50. Функция Число() такую строку не примет. Чистим вручную:
Функция ЧислоИзСтроки(Знач Значение)
Значение = СтрЗаменить(Значение, " ", "");
Значение = СтрЗаменить(Значение, Символы.НПП, "");
Значение = СтрЗаменить(Значение, ",", ".");
Если Значение = "" Тогда
Возврат 0;
КонецЕсли;
Попытка
Возврат Число(Значение);
Исключение
Возврат 0;
КонецПопытки;
КонецФункции
Дату вида 07.10.2026 собирают из частей: Дата(Число(Сред(Стр, 7, 4)), Число(Сред(Стр, 4, 2)), Число(Сред(Стр, 1, 2))). Для строки 07.10.2026 получится 7 октября 2026 года.
Если файл в формате xlsx
Когда вместо CSV прислали книгу Excel, переводить её в текст не обязательно. Объект ТабличныйДокумент читает xlsx и ods методом Прочитать, после чего значения берут из ячеек через ПолучитьОбласть или Область("R2C1").Текст. Файл читают на сервере, куда его заранее передали.
Чтение и разбор XML в 1С
Для XML у платформы три уровня. Выбор зависит от размера файла и от того, нужна ли схема.
| Способ | Память | Удобство | Когда подходит |
|---|---|---|---|
ЧтениеXML | минимум, потоковое чтение | ниже, идём по узлам вручную | большие файлы, выгрузки на сотни МБ |
ПостроительDOM | весь документ в памяти | поиск элементов по имени | файлы до десятков МБ, сложная вложенность |
ФабрикаXDTO | весь документ в памяти | объекты со свойствами | есть XSD-схема, обмен по формату |
Потоковое чтение: ЧтениеXML
Пусть файл выглядит так: <Товар Артикул="А-15"><Наименование>Бумага A4</Наименование></Товар>. Читаем атрибут и текст элемента:
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ИмяФайла);
Артикул = "";
Пока Чтение.Прочитать() Цикл
Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
Если Чтение.Имя = "Товар" Тогда
Артикул = Чтение.ПолучитьАтрибут("Артикул");
ИначеЕсли Чтение.Имя = "Наименование" Тогда
Чтение.Прочитать(); // переходим к текстовому узлу
Если Чтение.ТипУзла = ТипУзлаXML.Текст Тогда
Наименование = Чтение.Значение;
Сообщить(Артикул + " — " + Наименование);
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Чтение.Закрыть();
Каждый вызов Прочитать() сдвигает курсор на следующий узел: начало элемента, текст, конец элемента. Поэтому значение элемента лежит не в самом узле Наименование, а в следующем за ним текстовом узле.
Через DOM: поиск по имени элемента
Если структура глубокая и нужно прыгать между ветками, проще загрузить документ в дерево:
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ИмяФайла);
Построитель = Новый ПостроительDOM;
Документ = Построитель.Прочитать(Чтение);
Чтение.Закрыть();
Для Каждого Узел Из Документ.ПолучитьЭлементыПоИмени("Товар") Цикл
Артикул = Узел.ПолучитьАтрибут("Артикул");
Текст = Узел.ТекстовоеСодержимое;
КонецЦикла;
ТекстовоеСодержимое склеивает текст всех вложенных узлов. Для элемента с одним вложенным Наименование это ровно его значение; для сложного узла лучше спуститься к нужному дочернему элементу.
XDTO и JSON
Когда к файлу есть XSD-схема, удобнее ФабрикаXDTO.ПрочитатьXML(Чтение, Тип): на выходе объект, у которого элементы доступны как свойства. Это путь для обменов по утверждённым форматам.
JSON читают похоже на XML, только объектом ЧтениеJSON:
Чтение = Новый ЧтениеJSON;
Чтение.ОткрытьФайл(ИмяФайла);
Данные = ПрочитатьJSON(Чтение, Истина); // Истина — получить Соответствие
Чтение.Закрыть();
Второй параметр Истина нужен, если ключи в JSON содержат пробелы или символы, недопустимые в именах свойств структуры.
Двоичные данные и потоки: чтение файлов любого формата
Картинки, PDF, архивы и файлы без понятной структуры читают как набор байтов.
ДвоичныеДанные: файл целиком
Данные = Новый ДвоичныеДанные(ИмяФайла);
РазмерБайт = Данные.Размер();
Адрес = ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор);
Так файл прикладывают к справочнику, кладут в хранилище значения или передают между клиентом и сервером. Из двоичных данных можно получить текст: ПолучитьСтрокуИзДвоичныхДанных(Данные, КодировкаТекста.UTF8). Или открыть поток Данные.ОткрытьПотокДляЧтения() и передать его в ЧтениеТекста — оно принимает поток вместо имени файла. Тогда временный файл на диске не нужен.
Потоки и ЧтениеДанных
Потоковые объекты появились в 8.3.9. Они читают файл кусками и не загружают его в память. Пример: проверяем по первым байтам, что присланный «xlsx» — действительно ZIP-архив (сигнатура PK, байты 80 и 75):
Поток = ФайловыеПотоки.ОткрытьДляЧтения(ИмяФайла);
Чтение = Новый ЧтениеДанных(Поток);
Байт1 = Чтение.ПрочитатьБайт();
Байт2 = Чтение.ПрочитатьБайт();
Чтение.Закрыть();
Поток.Закрыть();
ЭтоАрхив = (Байт1 = 80 И Байт2 = 75);
Большой файл читают блоками через буфер:
Поток = ФайловыеПотоки.ОткрытьДляЧтения(ИмяФайла);
Буфер = Новый БуферДвоичныхДанных(65536); // 64 КБ
Прочитано = Поток.Прочитать(Буфер, 0, Буфер.Размер);
Пока Прочитано > 0 Цикл
// обработка первых Прочитано байт буфера
Прочитано = Поток.Прочитать(Буфер, 0, Буфер.Размер);
КонецЦикла;
Поток.Закрыть();
Метод потока Прочитать возвращает число реально прочитанных байт. На последнем блоке оно меньше размера буфера, поэтому обрабатывайте ровно Прочитано байт, а не весь буфер.
Кодировки, пути и где выполняется код
Когда код чтения написан верно, а файл всё равно не читается, причину почти всегда ищут в этих трёх местах.
Кодировка
Кодировку указывайте явно вторым параметром. Перечисление КодировкаТекста содержит UTF8, ANSI (в русской Windows это windows-1251), OEM (cp866), UTF16 и Системная. Можно передать и строку: "windows-1251", "UTF-8".
Как узнать ошибку кодировки по виду текста:
- 🔤
Приветвместо «Привет» — файл в UTF-8, а читаете как ANSI; - ❓ ромбики с вопросом
�— файл в windows-1251, а читаете как UTF-8; - 📟 буквы вроде
ЏаЁўҐв— файл в OEM (так пишут старые консольные программы и bat-файлы).
Выгрузки из Excel «CSV (разделители — запятые)» в русской Windows обычно сохраняются в windows-1251, а «CSV UTF-8» — в UTF-8 с меткой BOM. Если источник неизвестен, прочитайте первые три байта через ЧтениеДанных: 239, 187, 191 означают BOM UTF-8.
Путь к файлу
- 🖥️ Код на сервере видит диски сервера 1С, а не компьютера пользователя. Путь
C:\Users\buh\Desktop\price.csvв серверной процедуре ищется на сервере, где такой папки нет. - 🐧 Если сервер на Linux, пути пишутся через
/и чувствительны к регистру:Price.csvиprice.csv— разные файлы. - 🌐 Сетевая папка
\\fileserver\obmenдоступна серверу только от имени учётной записи, под которой запущена служба агента сервера 1С. Права пользователя Windows здесь не помогают. - 🔀 Разделитель пути для текущей ОС возвращает
ПолучитьРазделительПути().
Файл с компьютера пользователя на сервер
Типовая схема для управляемых форм:
- На клиенте пользователь выбирает файл, и он помещается во временное хранилище (
НачатьПомещениеФайловили асинхронныйПоместитьФайлНаСерверАсинхв новых версиях платформы). - На сервер передаётся адрес. Там
ПолучитьИзВременногоХранилища(Адрес)возвращаетДвоичныеДанные. - Данные пишут во временный файл
ПолучитьИмяВременногоФайла("csv")или сразу открывают потокОткрытьПотокДляЧтения(). - После чтения временный файл удаляют:
УдалитьФайлы(ИмяВременногоФайла).
В веб-клиенте прямого доступа к диску пользователя нет вообще, поэтому этот путь — единственный рабочий.
Обработка ошибок при чтении и скорость
Проверка и перехват ошибок
Перед открытием проверьте, что файл есть:
Файл = Новый Файл(ИмяФайла);
Если Не Файл.Существует() Тогда
Сообщить("Файл не найден: " + ИмяФайла);
Возврат;
КонецЕсли;
Само чтение оборачивайте в Попытка, и закрывайте файл в обеих ветках. Иначе после ошибки файл останется занятым до завершения сеанса:
Чтение = Неопределено;
Попытка
Чтение = Новый ЧтениеТекста(ИмяФайла, КодировкаТекста.UTF8);
Строка = Чтение.ПрочитатьСтроку();
Пока Строка <> Неопределено Цикл
ОбработатьСтроку(Строка);
Строка = Чтение.ПрочитатьСтроку();
КонецЦикла;
Чтение.Закрыть();
Исключение
Если Чтение <> Неопределено Тогда
Чтение.Закрыть();
КонецЕсли;
ЗаписьЖурналаРегистрации("Загрузка файла", УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение;
КонецПопытки;
Типичные причины исключения при открытии:
- 🔒 файл открыт в Excel — он держит книгу и CSV в монопольном режиме, закройте его;
- 🚫 у службы сервера 1С нет прав на папку;
- 📁 опечатка в пути или файл лежит на другой машине;
- 🧩 в XML нарушена структура —
ЧтениеXMLупадёт на строке с ошибкой, и номер строки будет в тексте исключения.
Скорость на больших файлах
- 📏 Для файлов больше нескольких десятков мегабайт — только
ЧтениеТекста,ЧтениеXMLили потоки.ТекстовыйДокументи DOM держат всё в памяти рабочего процесса. - 🗂️ Не делайте запрос к базе на каждой строке файла. Сначала соберите артикулы в
ТаблицаЗначений, потом одним запросом найдите все элементы справочника. - 🧱 Записывайте объекты пачками по 500–1000 штук внутри транзакции, а не одной транзакцией на весь файл: длинная транзакция держит блокировки и мешает другим пользователям.
- ⚙️ Тяжёлую загрузку запускайте на сервере, а лучше фоновым заданием, чтобы клиент не висел.
- 🔁 Сложение строк
Поле = Поле + Символна очень длинных строках медленное. Если в CSV строки по тысячи символов, разбирайте строку функциямиСтрНайтииСредпо позициям разделителей.
Частые вопросы
Можно ли прочитать файл, который сейчас открыт другой программой?
КопироватьФайл или попросите закрыть его.Как прочитать файл с FTP или по ссылке?
HTTPСоединение или FTPСоединение во временный файл, а затем читайте его обычным способом.Как прочитать только последние строки большого лога?
ФайловыйПоток, перейдите ближе к концу методом Перейти и прочитайте хвост. Читать весь файл ради последних 100 строк незачем.Чем ЧтениеТекста отличается от ЧтениеДанных?
ЧтениеТекста работает с символами и строками в заданной кодировке. ЧтениеДанных работает с байтами и числами, подходит для двоичных форматов и проверки сигнатур.