Чтение файла в строковую переменную на встроенном языке 1С 8.3
Содержание
Чтобы получить содержимое файла в виде строки в 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 |
| сотни МБ с клиента | не гоните через временное хранилище целиком — кладите файл в сетевую папку, доступную серверу, и читайте там |
Частые вопросы
Можно ли прочитать файл в строку прямо на клиенте?
Чем ПолучитьСтрокуИзДвоичныхДанных отличается от Base64Строка?
Как узнать кодировку, если файл присылают разные контрагенты?
Почему в строке после чтения лишние пустые строки?
ВК+ПС прочитан через двоичные данные, и при разбивке по ПС остались символы ВК. Удалите их через СтрЗаменить до разбивки.Нужно ли удалять данные из временного хранилища?
УдалитьИзВременногоХранилища() сразу после чтения, чтобы не держать память сервера.