Почему изменяется длина строки Base64 после сохранения в файл или Excel и как восстановить двоичные данные в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При интеграции систем и передаче файлов через текстовые форматы разработчики часто сталкиваются с кодированием в формат Base64. Нередко возникает ситуация: двоичные данные преобразуются в строку, записываются в текстовый файл или выгружаются в таблицу Microsoft Excel, но при обратном чтении длина строки оказывается совершенно другой. Разберем по шагам, почему так происходит, опасна ли разница в длине для целостности файлов и как правильно работать с такими строками в платформе 1С:Предприятие.

Анализ проблемы: почему различается длина строки

Рассмотрим типовую ситуацию. Исходный файл кодируется в Base64 с помощью встроенной функции платформы 1С:


ДД = Новый ДвоичныеДанные("C:\katalog\temp.png");
Текст64 = Base64Строка(ДД);
Сообщить(СтрДлина(Текст64));

При проверке длины полученной строки мы видим одно число (например, 236 902 символа). Если затем мы сохраняем эту строку в текстовый документ через объект ТекстовыйДокумент и читаем его построчно, длина уменьшается (в примере до 229 724 символов). А если строка выгружалась в ячейку Excel, длина строки после чтения становится ровно 32 767 символов. Выясним причину каждого из этих явлений.

  1. Стандарт MIME (RFC 2045) и автоматический перенос строк в 1С. Функция Base64Строка(), а также метод ПолучитьBase64СтрокуИзДвоичныхДанных() формируют строку в соответствии со спецификацией MIME. По этому стандарту непрерывный поток символов Base64 разбивается на строки фиксированной длины — ровно по 64 символа, после чего вставляются невидимые символы перевода строки и возврата каретки (CRLF, то есть Символы.ВК + Символы.ПС). Именно эти служебные пары символов увеличивают общий размер исходной строки на несколько тысяч знаков.
  2. Особенности построчного чтения в объекте ТекстовыйДокумент. Метод ПолучитьСтроку() возвращает строку без завершающих символов перевода строки. Если читать файл в цикле и складывать результат через оператор конкатенации +, все символы CRLF отбрасываются. В результате длина строки становится меньше ровно на количество исключенных служебных символов.
  3. Аппаратное ограничение ячеек Microsoft Excel. В Excel действует строгое архитектурное ограничение: в одной ячейке листа не может храниться более 32 767 символов. Любой текст большей длины будет безвозвратно обрезан при записи, что приведет к повреждению закодированных двоичных данных.

Восстановление данных: почему картинка все равно открывается

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

Однако с Excel такой трюк не сработает: обрезка до 32 767 символов безвозвратно уничтожает оставшуюся часть файла, поэтому восстановить исходные двоичные данные из одной ячейки невозможно.

Способ 1. Правильная запись и чтение текста без потери форматирования

Чтобы избежать искажения служебных символов и не тратить ресурсы системы на конкатенацию сотен тысяч строк в цикле, заменим ТекстовыйДокумент на объекты ЗаписьТекста и ЧтениеТекста. Они позволяют работать с текстом как с единым массивом данных.

Запись строки Base64 в файл:


Запись = Новый ЗаписьТекста("C:\katalog\b64.txt", КодировкаТекста.UTF8);
Запись.Записать(Текст64);
Запись.Закрыть();

Чтение файла целиком одной операцией:


Чтение = Новый ЧтениеТекста("C:\katalog\b64.txt", КодировкаТекста.UTF8);
ТекстИзФайла = Чтение.Прочитать();
Чтение.Закрыть();

// Восстановление двоичных данных
ДДВосстановленные = Base64Значение(ТекстИзФайла);
ДДВосстановленные.Записать("C:\katalog\restored.png");

При таком подходе длина строки останется в точности такой же, как при первичном кодировании, а чтение выполнится мгновенно.

Способ 2. Прямая работа с двоичными данными без Base64

Посмотрим на задачу шире: если промежуточный текстовый файл не требуется для передачи через внешние REST- или SOAP-сервисы, преобразовывать файл в Base64 вообще не имеет практического смысла. Платформа 1С позволяет напрямую читать и сохранять двоичные файлы без промежуточного перевода в текст, что экономит память и процессорное время:


// Чтение файла в двоичные данные
Двоичные = Новый ДвоичныеДанные("C:\katalog\temp.png");

// Сохранение двоичных данных в новый файл
Двоичные.Записать("C:\katalog\temp_copy.png");

Способ 3. Передача больших данных и файлов в Microsoft Excel

Если стоит задача передать изображение или большой файл внутрь документа Excel, рассмотрим два правильных сценария обхода лимита в 32 767 знаков:

  1. Вставка через графический слой Excel. Если файл является изображением, которое пользователь должен видеть в отчете, не нужно помещать его код в ячейку. Картинка добавляется в коллекцию графических фигур листа через COM-объект:
    
    Эксел = Новый COMОбъект("Excel.Application");
    Книга = Эксел.Workbooks.Open("C:\katalog\katalog.xlsx");
    Лист = Книга.Sheets(1);
    
    // Параметры: ПутьКФайлу, СвязатьСФайлом, СохранятьСДокументом, Лево, Верх, Ширина, Высота
    Лист.Shapes.AddPicture("C:\katalog\temp.png", Ложь, Истина, 50, 50, 200, 150);
    
    Книга.Save();
    Эксел.Quit();
    
  2. Разбиение строки Base64 на блоки. Если требуется сохранить закодированный файл внутри книги Excel в качестве хранилища данных, строку необходимо программно нарезать на фрагменты длиной до 32 000 символов и последовательно разместить их в нескольких соседних ячейках одной колонки или строки, а при чтении — объединить обратно в одну непрерывную переменную перед вызовом Base64Значение().
← На главную