Чтение файла в строковую переменную на встроенном языке 1С 8.3

· 9 мин

Содержание

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

Типичная ситуация: из банка или маркетплейса приходит выгрузка в TXT, CSV или JSON, и обработке нужен весь текст целиком, чтобы разобрать его по строкам или передать в ПрочитатьJSON. Ниже — рабочие варианты под разные условия: файл на сервере, файл у пользователя, неизвестная кодировка, файл на сотни мегабайт.

Три базовых способа прочитать текстовый файл в строку

Все три способа работают в платформе 8.3 и дают одинаковый результат — значение типа Строка. Разница в удобстве и в том, что ещё вы получаете «в нагрузку».

СпособКогда братьОсобенности
ЧтениеТекстаОсновной вариант для текстовых файловУмеет читать целиком, по строкам и порциями; сам переводит ВК+ПС в ПС
ТекстовыйДокументНужен ещё и построчный доступ по номеру, вывод на формуДержит весь документ в памяти, для больших файлов тяжелее
ДвоичныеДанные + ПолучитьСтрокуИзДвоичныхДанных()Файл уже лежит в памяти, хранилище, реквизите или пришёл по HTTPПеревод строк не меняет, кодировку задаёте явно

Способ 1. Объект ЧтениеТекста

Это самый прямой путь. Функцию удобно держать в общем модуле с флажком «Сервер».

Функция ПрочитатьФайлВСтроку(ИмяФайла, Кодировка = Неопределено) Экспорт

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

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

	// Для пустого файла Прочитать() возвращает Неопределено
	Возврат ?(Текст = Неопределено, "", Текст);

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

Не забывайте Закрыть(). Пока объект чтения жив, файл остаётся открытым, и его нельзя удалить или перезаписать из той же процедуры.

Способ 2. ТекстовыйДокумент

Подходит, если после чтения вы всё равно будете ходить по строкам через КоличествоСтрок() и ПолучитьСтроку(Н) или показывать текст на форме в поле текстового документа.

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

КодировкаТекста.ANSI на русской Windows означает windows-1251. Для файлов из старых DOS-программ бывает нужна КодировкаТекста.OEM (cp866).

Способ 3. Через двоичные данные

Файл загружается в память как есть, байт в байт, а строкой становится уже потом.

ДД = Новый ДвоичныеДанные(ИмяФайла);
Текст = ПолучитьСтрокуИзДвоичныхДанных(ДД, "windows-1251");

Второй параметр принимает и значение КодировкаТекста, и строковое имя кодировки: "UTF-8", "windows-1251", "cp866", "KOI8-R". Если его не указать, платформа считает данные UTF-8.

Как получить файл как строку из двоичных данных и потоков

Строка — не всегда то, что на самом деле нужно. Если файл картинка, PDF или архив, превращать его в «текст» бессмысленно: вы получите мусор. Для передачи такого файла в JSON, XML или HTTP-запрос его кодируют в Base64.

Двоичный файл в строку Base64

ДД = Новый ДвоичныеДанные(ИмяФайла);
Строка64 = Base64Строка(ДД);

// Обратно: из строки в двоичные данные и в файл
ДДНазад = Base64Значение(Строка64);
ДДНазад.Записать(ИмяНовогоФайла);

В новых версиях платформы есть пара ПолучитьBase64СтрокуИзДвоичныхДанных() и ПолучитьДвоичныеДанныеИзBase64Строки() — делают то же самое. Строка Base64 может содержать переводы строк. Если принимающая сторона их не ждёт, уберите: СтрЗаменить(СтрЗаменить(Строка64, Символы.ВК, ""), Символы.ПС, "").

Размер растёт примерно на треть: файл 3 МБ превращается в строку около 4 МБ.

Чтение через поток

Потоки нужны, когда файл не хочется держать в памяти дважды или когда данные приходят не из файла, а, например, из ответа HTTP-сервиса. ЧтениеТекста умеет работать поверх потока:

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

Если двоичные данные уже есть в переменной, поток из них открывается методом ДД.ОткрытьПотокДляЧтения(). Дальше та же схема с ЧтениеТекста.

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

Кодировка файла, BOM и переводы строк

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

Как понять, в какой кодировке файл

  • 🔤 UTF-8 — современный стандарт: JSON, выгрузки маркетплейсов, большинство веб-сервисов.
  • 🪟 windows-1251 (ANSI) — старые CSV из Excel, выгрузки из клиент-банков, файлы из 1С 7.7.
  • 💾 cp866 (OEM) — вывод консольных утилит Windows, старые DOS-форматы.
  • 📄 UTF-16 — некоторые экспорты Windows и выгрузки «Юникод» из Excel.

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

ДД = Новый ДвоичныеДанные(ИмяФайла);
Текст = ПолучитьСтрокуИзДвоичныхДанных(ДД, "UTF-8");

Если СтрНайти(Текст, Символ(65533)) > 0 Тогда
	// Скорее всего, это не UTF-8 — пробуем windows-1251
	Текст = ПолучитьСтрокуИзДвоичныхДанных(ДД, "windows-1251");
КонецЕсли;

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

Невидимый символ BOM в начале строки

Многие программы пишут в начало UTF-8-файла метку BOM — три служебных байта. При чтении она может превратиться в невидимый символ с кодом 65279 в первой позиции строки. Симптомы странные: ПрочитатьJSON падает на первом символе, сравнение заголовка CSV с ожидаемым текстом даёт Ложь, хотя на экране всё одинаково.

Лечится одной проверкой после чтения:

Если СтрДлина(Текст) > 0 И КодСимвола(Текст, 1) = 65279 Тогда
	Текст = Сред(Текст, 2);
КонецЕсли;

При записи файла через ЗаписьТекста с КодировкаТекста.UTF8 платформа сама добавляет BOM. Если принимающая система его не понимает, сформируйте двоичные данные функцией ПолучитьДвоичныеДанныеИзСтроки(Текст, "UTF-8", Ложь) — третий параметр отключает метку — и запишите их методом Записать().

Переводы строк

В Windows строка заканчивается парой символов ВК+ПС, в Linux — одним ПС. Объект ЧтениеТекста по умолчанию приводит ВК+ПС к ПС. А ПолучитьСтрокуИзДвоичныхДанных() ничего не меняет.

Отсюда частая ошибка: текст получили через двоичные данные, разбили СтрРазделить(Текст, Символы.ПС), и в конце каждой строки остался невидимый ВК. Сравнения и преобразования в число ломаются. Перед разбивкой уберите лишнее: Текст = СтрЗаменить(Текст, Символы.ВК, "").

Файл у пользователя: временное хранилище и временные файлы

Код на сервере видит файловую систему сервера, а не компьютера бухгалтера. Путь C:\Users\Ivanov\Desktop\выписка.txt на сервере не существует. Кроме того, служба сервера 1С работает под своей учётной записью (по умолчанию USR1CV8), и у неё может не быть прав даже на сетевую папку, которую видит пользователь.

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

Загрузка файла с клиента и чтение на сервере

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

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

&НаСервереБезКонтекста
Функция ПрочитатьТекстНаСервере(Адрес)
	ДД = ПолучитьИзВременногоХранилища(Адрес);
	УдалитьИзВременногоХранилища(Адрес);
	Возврат ПолучитьСтрокуИзДвоичныхДанных(ДД, "UTF-8");
КонецФункции

Четвёртый параметр Истина открывает диалог выбора файла. Пятый — идентификатор формы: хранилище живёт, пока открыта форма, и освободится само, даже если вы забудете удалить данные.

Когда нужен временный файл на сервере

Некоторые объекты принимают только имя файла: например, ТекстовыйДокумент.Прочитать() или внешние компоненты. Тогда двоичные данные сначала записывают во временный файл:

ИмяВрем = ПолучитьИмяВременногоФайла("txt");
ДД.Записать(ИмяВрем);
Попытка
	ТД = Новый ТекстовыйДокумент;
	ТД.Прочитать(ИмяВрем, КодировкаТекста.UTF8);
	Текст = ТД.ПолучитьТекст();
Исключение
	УдалитьФайлы(ИмяВрем);
	ВызватьИсключение;
КонецПопытки;
УдалитьФайлы(ИмяВрем);

ПолучитьИмяВременногоФайла() только придумывает уникальное имя в каталоге временных файлов, сам файл не создаёт. Удалять его — ваша забота: иначе каталог временных файлов сервера разрастается до гигабайт.

Файл в реквизите типа ХранилищеЗначения

Если файл хранится в базе в реквизите типа ХранилищеЗначения, читать с диска ничего не нужно: ДД = Объект.ФайлВыгрузки.Получить(), дальше — ПолучитьСтрокуИзДвоичныхДанных(). В типовых конфигурациях на БСП присоединённые файлы читают через программный интерфейс подсистемы работы с файлами, а не напрямую из таблиц.

Обработка ошибок при чтении файла

Чтение файла — внешняя операция. Файла может не оказаться, он может быть занят другой программой, у службы может не быть прав. Без обработки пользователь увидит системное сообщение об ошибке вызова метода, а обработка оборвётся на середине.

Проверки до чтения

Файл = Новый Файл(ИмяФайла);
Если Не Файл.Существует() Или Не Файл.ЭтоФайл() Тогда
	ВызватьИсключение СтрШаблон("Файл не найден: %1", ИмяФайла);
КонецЕсли;

Если Файл.Размер() = 0 Тогда
	Возврат "";
КонецЕсли;

Чтение в попытке с закрытием объекта

Чтение = Неопределено;
Попытка
	Чтение = Новый ЧтениеТекста(ИмяФайла, КодировкаТекста.UTF8);
	Текст = Чтение.Прочитать();
	Чтение.Закрыть();
Исключение
	Если Чтение <> Неопределено Тогда
		Чтение.Закрыть();
	КонецЕсли;
	ЗаписьЖурналаРегистрации("Загрузка файла", УровеньЖурналаРегистрации.Ошибка, , ,
		ОписаниеОшибки());
	ВызватьИсключение СтрШаблон("Не удалось прочитать файл %1. %2", ИмяФайла, ОписаниеОшибки());
КонецПопытки;

Запись в журнал регистрации пригодится, если обработка работает в регламентном задании и сообщение некому показать.

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

Большие файлы: как читать быстро и без перерасхода памяти

Файл на 5–10 МБ можно читать целиком, это занимает доли секунды. На 300–500 МБ подход «весь файл в одну строку» уже опасен: строка в памяти занимает примерно вдвое больше байт, чем текст в UTF-8, а к ней добавляются копии при СтрЗаменить и СтрРазделить. Рабочий процесс сервера раздувается, а в 32-разрядном клиенте можно упереться в лимит памяти.

Построчное чтение

Если файл обрабатывается строка за строкой (CSV, лог, выписка), всю строку собирать не нужно:

Чтение = Новый ЧтениеТекста(ИмяФайла, КодировкаТекста.UTF8);
Строка = Чтение.ПрочитатьСтроку();
Пока Строка <> Неопределено Цикл
	ОбработатьСтроку(Строка);
	Строка = Чтение.ПрочитатьСтроку();
КонецЦикла;
Чтение.Закрыть();

В памяти одновременно держится только текущая строка.

Чтение порциями

Для файлов без разбивки на строки (огромный JSON в одну строку) метод Прочитать() принимает число символов:

Порция = Чтение.Прочитать(1048576); // около миллиона символов
Пока Порция <> Неопределено Цикл
	ОбработатьПорцию(Порция);
	Порция = Чтение.Прочитать(1048576);
КонецЦикла;

Для потокового разбора JSON удобнее сразу ЧтениеJSON с ОткрытьФайл(): он читает файл последовательно и не требует загружать его в строку.

Не склеивайте строки в цикле

Результат = Результат + Строка на каждой итерации создаёт новую строку и копирует всё накопленное. На 100 000 строк это заметно медленнее. Складывайте части в массив и соединяйте один раз:

Части = Новый Массив;
// ... в цикле: Части.Добавить(Строка);
Результат = СтрСоединить(Части, Символы.ПС);
Размер файлаРекомендуемый способ
до 10–20 МБЧтениеТекста.Прочитать() целиком
десятки–сотни МБ, построчный форматцикл ПрочитатьСтроку()
большой файл без строкПрочитать(N) порциями или потоковые объекты ЧтениеJSON / ЧтениеXML
сотни МБ с клиентане гоните через временное хранилище целиком — кладите файл в сетевую папку, доступную серверу, и читайте там

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

Можно ли прочитать файл в строку прямо на клиенте?
В тонком клиенте под Windows синхронные методы работы с файлами доступны, если они разрешены в свойствах конфигурации. В веб-клиенте и при режиме без синхронных вызовов используйте асинхронные методы или передачу файла на сервер через временное хранилище.
Чем ПолучитьСтрокуИзДвоичныхДанных отличается от Base64Строка?
Первая функция декодирует байты как текст в заданной кодировке. Вторая не декодирует, а кодирует любые байты в набор латинских символов. Base64 нужен для картинок, PDF и архивов.
Как узнать кодировку, если файл присылают разные контрагенты?
Надёжного автоопределения кодировки в платформе нет. Используйте проверку на символ с кодом 65533 после чтения как UTF-8 или договоритесь о формате обмена.
Почему в строке после чтения лишние пустые строки?
Файл с окончаниями ВК+ПС прочитан через двоичные данные, и при разбивке по ПС остались символы ВК. Удалите их через СтрЗаменить до разбивки.
Нужно ли удалять данные из временного хранилища?
Если указан идентификатор формы, данные удалятся при её закрытии. Но для крупных файлов лучше вызвать УдалитьИзВременногоХранилища() сразу после чтения, чтобы не держать память сервера.