1с 8.3 двоичные данные в файл. Работа с двоичными данными. Побитовые логические операции с буфером двоичных данных

Реализовано в версии 8.3.10.2168.

Мы постепенно наращиваем функциональность работы с двоичными данными. Для этого есть несколько причин. Во-первых, мы реализовали не всё из того, что было нами задумано. А во-вторых, в процессе обсуждения новых возможностей, мы получили от вас ряд пожеланий, которые мы также решили реализовать.

Новые функции для преобразования двоичных данных в разные форматы

В глобальный контекст мы добавили большое количество новых функций для преобразования двоичных данных. Так, например, вы можете выполнять прямое и обратное преобразование двоичных данных в обычную строку, строку формата Base64 и строку формата BinHex . Кроме этого сами двоичные данные вы можете преобразовать в форматы Base64 , BinHex и обратно.

Аналогичные преобразования поддерживаются и для типа БуферДвоичныхДанных . Кроме этого буфер двоичных данных вы можете преобразовывать в двоичные данные и обратно.

Помимо этого две новые функции позволяют разделить двоичные данные на несколько частей, и наоборот, объединить несколько объектов типа ДвоичныеДанные в один. При этом новый объект будет содержать данные всех частей в том порядке, который вы укажете.

Эти функции по своему смыслу аналогичны разделению и объединению файлов, но во многих случаях они более эффективны. Потому что не нужно предварительно сохранять двоичные данные в файл, и потому, что при разделении отсутствует лишнее копирование данных.

Добавление возможности работы с потоками тем объектам, которые работают с файлами

Поскольку использование двоичных данных во многом связано с файловыми операциями, мы посчитали совершенно логичным и естественным добавить работу с потоками в те объекты, которые сейчас тем или иным образом читают и пишут файлы.

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

  • ЧтениеТекста и ЗаписьТекста ;
  • ЧтениеFastInfoSet и ЗаписьFastInfoSet ;
  • ЧтениеHtml и ЗаписьHtml ;
  • ЧтениеJSON и ЗаписьJSON ;
  • ЧтениеXML и ЗаписьXML ;
  • ЧтениеZipФайла и ЗаписьZipФайла .

Вы можете получать тело как поток, когда работаете с HTTP:

  • HTTPЗапрос и HTTPОтвет ;
  • HTTPСервисЗапрос и HTTPСервисОтвет .
  • ТекстовыйДокумент ;
  • ТабличныйДокумент ;
  • ФорматированныйДокумент ;
  • ГеографическаяСхема ;
  • ГрафическаяСхема ;
  • FTPСоединение .

Запись в поток доступна теперь при работе с типами Картинка и ПреобразованиеККаноническомуXML . А кроме этого работа с потоками поддерживается теперь в различных методах, которые есть у типов ПреобразованиеXSL , МенеджерКриптографии , СертификатКриптографии и ХешированиеДанных .

Эффективное копирование с помощью чтения и записи данных

Инструменты для работы с двоичными данными, которые мы реализовали , позволяли копировать потоки. Но на больших объёмах данных эта операция выполнялась не очень эффективно.

Поэтому у типа ЧтениеДанных мы реализовали новый метод КопироватьВ() . Он не только устраняет эту проблему, но и упрощает текст, делая его более понятным.

Например, раньше можно было получить двоичные данные из одного потока, и записать их в другой поток.

Теперь нет необходимости получать двоичные данные, копирование выполняется ещё на этапе чтения данных.

Приятным моментом является то, что копировать можно не только в поток, но и в объект ЗаписьДанных . Этот вариант удобен тогда, когда, помимо данных из исходного потока, вам требуется записать в выходной поток какие-то свои данные.

Побитовые логические операции с буфером двоичных данных

Теперь вы можете использовать побитовые логические операции при работе с буферами двоичных данных. В результате этих операций в исходный буфер будет записан результат побитового объединения исходных байтов и байтов в заданном буфере по правилам выбранной логической операции. Мы реализовали следующие операции:

  • ЗаписатьПобитовоеИ() ;
  • ЗаписатьПобитовоеИли() ;
  • ЗаписатьПобитовоеИсключительноеИли();
  • ЗаписатьПобитовоеИНе() ;
  • Инвертировать() .

Хорошим примером использования побитовых логических операций является задача декодирования формата обмена с торговым оборудованием. Например, формат обмена с торговым оборудованием описывается полем длиной в 1 байт. Это поле содержит набор признаков, описывающих номенклатуру товара:

  • Биты 0-2: налоговая ставка;
  • Бит 3: 0 - штучный товар, 1 - весовой товар;
  • Бит 4: 0 - разрешить продажу, 1 - запретить продажу;
  • Бит 5: 0 - разрешить подсчет количества, 1 - запретить подсчет количества;
  • Бит 6: 0 - одиночная продажа запрещена, 1 - одиночная продажа разрешена;
  • Бит 7: зарезервировано.

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

Получение числа из шестнадцатеричных и двоичных литералов

  • ЧислоИзШестнадцатеричнойСтроки() ;
  • ЧислоИзДвоичнойСтроки() .

Двоичные литералы удобно использовать для определения масок при совместном использовании с побитовыми операциями. Например, в предыдущем примере с разбором формата обмена с торговым оборудованием, маски задаются с использованием десятичных чисел. Это не очень удобно, так как при написании и чтении кода нужно постоянно производить мысленную трансляцию десятичного числа в двоичную систему.

Вместо этого гораздо удобнее использовать двоичные литералы. При этом код становится более наглядным и вероятность ошибки значительно уменьшается.

Шестнадцатеричные литералы удобно использовать при разборе технических форматов: форматы изображений, звука, видео.

Изменения в технологии внешних компонент NativeAPI

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

Теперь мы убираем все эти ограничения. Обмен двоичными данными вы можете осуществлять в обе стороны и даже в веб-клиенте.

На работе существующих внешних компонент это никак не отразится. Они будут работать, как и раньше. А вот во вновь создаваемых компонентах вы сможете теперь в качестве параметров передавать объекты ДвоичныеДанные .

В хранилище значения можно сохранить почти любую информацию, например,

... картинки (фотки):

ТекИзображение.Объект = СпрТкани.Ссылка; ТекИзображение.ВидДанных = Перечисления.ВидыДополнительнойИнформацииОбъектов.Изображение; Хранилище = Новый ХранилищеЗначения(НоваяКартинка, Новый СжатиеДанных()); ТекИзображение.Хранилище = Хранилище.Получить();

// в этом месте он все выводит... ЭлементыФормы.ПолеКартинки1.Картинка = Хранилище.Получить(); ТекИзображение.Записать();

...табличный документ:

ТабДок=Новый ТабличныйДокумент; ТабДок.Вывести(ЭлементыФормы.ПолеТабличногоДокумента1); Хранилище=Новый ХранилищеЗначения(ТабДок); Записать();

КонецПроцедуры

Процедура ВосстановитьИзХранилищаНажатие(Элемент)

ТабДок=Хранилище.Получить(); Если ТабДок<>Неопределено Тогда ЭлементыФормы.ПолеТабличногоДокумента1.Вывести(ТабДок); КонецЕсли;

КонецПроцедуры

... произвольные файлы (двоичные данные):

ХЗ = Новый ХранилищеЗначения(Новый ДвоичныеДанные(файл));

Восьмерка поддерживает сжатие данных, помещаемых в хранилище:

ХЗ = Новый ХранилищеЗначения(Новый ДвоичныеДанные(файл),Новый СжатиеДанных(9));

... внешние обработки и отчеты:

Процедура ЗагрузитьОбработкуВХранилище(РеквизитТипХранилище)

СтепеньСжатия = Новый СжатиеДанных(9); //9 максимум РеквизитТипХранилище = Новый ХранилищеЗначения(Новый ДвоичныеДанные("c:\отчеты\отчет.epf", СтепеньСжатия));

КонецПроцедуры

Процедура ЗапуститьОбработкуИзХранилища(РеквизитТипХранилище)

ИмяВременногоФайла = КаталогВременныхФайлов()+"отчет.epf"; ДвоичныеДанные = РеквизитТипХранилище.Получить(); ДвоичныеДанные.Записать(ИмяВременногоФайла); ВнешняяОбработка = ВнешниеОбработки.Создать(ИмяВременногоФайла); ВнешняяОбработка.ПолучитьФорму().Открыть();

КонецПроцедуры

Работа с хранилищем

Если это были ДвоичныеДанные, то их можно восстановить из хранилища значения методом Получить и записать в файл методом Записать().

Если ТипЗнч(Хранилище) <> Тип("ДвоичныеДанные") Тогда

ДвоичныеДанные = Хранилище.Получить();

ДвоичныеДанные = Хранилище;

КонецЕсли; ДвоичныеДанные.Записать(ИмяФайла);

Если это был, например, Word-документ (doc-файл, или другой файл зарегистрированного типа), то его можно открыть так:

ЗапуститьПриложение(ИмяФайла);

Чтобы очистить поле типа Хранилище значения, нужно присвоить ему Неопределено:

РеквизитХранилище = Неопределено;

Работа с файлами и картинками во встроенном языке 1С:Предприятия 8

Назначение

В управляемом приложении реализован новый механизм работы с файлами. Он обеспечивает обмен файлами между информационной базой и клиентским приложением. Особенностью данного механизма является то, что он ориентирован на использование в тонком клиенте и Веб-клиенте и разработан с учетом ограничений на работу с файлами, накладываемыми веб-браузерами.

Механизм представляет собой набор методов, с помощью которых можно поместить данные, хранящиеся локально у пользователя, во временное хранилище информационной базы, перенести эту информацию из временного хранилища в базу данных и получить ее обратно на компьютер пользователя. Наиболее распространенные прикладные задачи, решаемые этим механизмом, – это хранение сопроводительной информации, например, изображений товаров, связанных с договорами документов и т. п.

Область действия методов

Временное хранилище

Временное хранилище - это специализированная область информационной базы, в которую могут быть помещены двоичные данные. Основное назначение – это временное хранение информации при клиент-серверном взаимодействии до ее переноса в базу данных.

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

Наиболее типичная решаемая временным хранилищем прикладная задача – обеспечение доступа к файлам или картинкам до того, как объект будет записан в информационную базу, например, в форме элемента.

Файл или двоичные данные, помещенные в хранилище, идентифицируются уникальным адресом, который в дальнейшем можно использовать в операциях записи, чтения или удаления. Этот адрес выдают методы записи файла во временное хранилище. Отдельный метод во встроенном языке позволяет определить, является ли переданный адрес адресом, указывающим на данные во временном хранилище.

Информационная база

Механизм позволяет получить доступ к двоичным данным, хранящимся в реквизитах типа ХранилищеЗначений.

Как и в случае временного хранилища, доступ к информации возможен через специальный адрес. Получить его можно через специальный метод, передав ссылку на объект или ключ записи регистра сведений, и имя реквизита. В случае табличной части дополнительно требуется передать и индекс строки табличной части.

Методы работы с файлами имеют ограничение при работе с реквизитами информационной базы. Для них, в отличие от временного хранилища, доступно только чтение информации, но не ее запись или удаление.

Описание методов работы с файлами

Сохранение данных во временное хранилище

Наиболее типичный сценарий использования данного механизма предусматривает первоначальное размещение данных пользователя во временное хранилище. Для этого предназначены два метода: ПоместитьФайл() и ПоместитьФайлВоВременноеХранилище().

Первый метод, ПоместитьФайл(), помещает файл из локальной файловой системы во временное хранилище. Метод может принимать целевой адрес в хранилище. Если же он не определен или является пустой строкой, то будет создан новый файл и метод вернет его адрес через соответствующий параметр.

Если параметр, определяющий интерактивный режим работы, равен Истина, то метод отобразит стандартное диалоговое окно выбора файла, в котором можно выбрать файл для помещения в хранилище. В этом случае метод также вернет адрес выбранного файла.

Как результат метод возвращает Ложь, если пользователь в интерактивном режиме отказался от совершения операции в диалоге выбора файла. Метод доступен только на клиенте.

Второй метод, ПоместитьФайлВоВременноеХранилище(), схож с предыдущим, за исключением того, что он доступен на сервере, а данные для записи во временное хранилище представляются не в виде пути в файловой системе, а в виде переменной типа ДвоичныеДанные. Точно так же, если не указан целевой адрес, создается новый файл в хранилище. Его адрес возвращается как результат функции.

Получение файла из временного хранилища

При записи объекта в информационную базу может понадобиться извлечь данные из временного хранилища и поместить их, например, в реквизит. Для этого есть соответствующий серверный метод - ПолучитьФайлИзВременногоХранилища(). Этот метод извлекает данные из временного хранилища и возвращает их как результат. Для этого необходимо указать адрес во временном хранилище. Этот адрес возвращают вышеописанные методы ПоместитьФайл() и ПоместитьФайлВоВременноеХранилище() в случае их успешного выполнения.

Удаление файла из временного хранилища

После того, как данные сохранены в реквизите, файл во временном хранилище можно удалить. Для этого есть метод УдалитьФайлИзВременногоХранилища(), который удаляет файл из временного хранилища. Метод принимает в параметре адрес файла во временном хранилище. Доступен на сервере.

Проверка адреса на принадлежность временному хранилищу

Адрес файла может указывать как на временное хранилище, так и на реквизит в информационной базе. Для проверки его типа существует метод ЭтоАдресВременногоХранилища().

Он проверяет, что переданный адрес является адресом, указывающим на хранилище. Возвращает Истина, если адрес указывает на временное хранилище. Метод доступен на сервере.

Получение адреса реквизита

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

Но прежде чем получить данные, например из реквизита, необходимо получить адрес этого реквизита. Для этого существует метод ПолучитьАдресФайлаВИнформационнойБазе().

Его назначение – вернуть адрес файла в информационной базе по исходным параметрам. Для этого необходимо передать ключ объекта (это может быть как ссылка на объект, так и ключ записи регистра сведений) и имя реквизита. Если нужно получить адрес файла, хранимого в реквизите табличной части, до имени реквизита в параметре, задающем имя реквизита, необходимо добавить имя табличной части и точку «.». Метод доступен как на клиенте, так и на сервере.

Получение файла из информационной базы

Метод ПолучитьФайл() получает файл из информационной базы и сохраняет его в локальную файловую систему пользователя. Первый параметр определяет адрес файла в реквизите или во временном хранилище файлов. Второй параметр определяет целевое расположение полученного файла. В не интерактивном режиме необходимо указать путь. В интерактивном режиме параметр является опциональным.

По умолчанию метод исполняется в интерактивном режиме, то есть последний параметр равен Истина. Это значит, что выдается диалоговое окно, в котором можно указать действие с полученным файлом: запустить его или сохранить по указанному пользователем расположению. Если активен интерактивный режим, а параметр Целевой путь к файлу на диске не указан, то операция открытия файла не доступна. Возвращает булевское значение. Ложь означает, что пользователь выбрал отмену операции в диалоговом окне сохранения файлов в интерактивном режиме.

Пример использования файловых методов

// Получение в интерактивном режиме файла с диска // и помещение его во временное хранилище &НаКлиенте Процедура ВыбратьФайлСДискаИЗаписать()

Перем ВыбранноеИмя; Перем АдресВременногоХранилища; Если ПоместитьФайл(АдресВременногоХранилища, ВыбранноеИмя, Истина) Тогда Объект.ИмяФайла = ВыбранноеИмя; ПоместитьФайлОбъекта(АдресВременногоХранилища); КонецЕсли;

КонецПроцедуры

// Копирование файла из временного хранилища в реквизит // справочника, запись объекта,удаление файла из временного // хранилища &НаСервере Процедура ПоместитьФайлОбъекта(АдресВременногоХранилища)

ЭлементСправочника = РеквизитФормыВЗначение("Объект"); ДвоичныеДанные = ПолучитьФайлИзВременногоХранилища(АдресВременногоХранилища); ЭлементСправочника.ДанныеФайла = Новый ХранилищеЗначения(ДвоичныеДанные); ФайлПутьНаДиске = Новый Файл(ЭлементСправочника.ИмяФайла); ЭлементСправочника.ИмяФайла = ФайлПутьНаДиске.Имя; ЭлементСправочника.Записать(); Модифицированность = Ложь; УдалитьФайлИзВременногоХранилища(АдресВременногоХранилища); ЗначениеВРеквизитФормы(ЭлементСправочника, "Объект");

КонецПроцедуры

// Считывание файла из реквизита и сохранение его // на локальном диске в интерактивном режиме &НаКлиенте Процедура ПрочитатьФайлИСохранитьНаДиск()

Адрес = ПолучитьАдресФайлаВИнформационнойБазе(Объект.Ссылка, "ДанныеФайла"); ПолучитьФайл(Адрес, Объект.ИмяФайла, Истина);

КонецПроцедуры

Поддержка адресов в поле картинки

Элемент управления Поле картинки поддерживает отображение картинки, заданной адресом файла во временном хранилище или в базе данных.

Для этого в свойстве Данные элемента формы необходимо задать реквизит строкового типа. Значение этого реквизита и будет интерпретироваться как адрес картинки.

Пример // Привязка поля картинки к адресу картинки во временном // хранилище. АдресКартинки реквизит формы строкового типа

ПоместитьФайл(АдресКартинки,Истина)

Картинка.Данные = АдресКартинки

Ограничения при работе с Веб-клиентом

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

Особенности при работе с ХранилищемЗначений на Клиенте

Проблема:

Когда у Документа в табличной части есть реквизит типа ХранилищеЗначений, то тормозит открытие формы документа, если в этом реквизите записаны данные большого размера.

Предполагаемая причина:

Возможно, при открытии формы, на клиент передается не ссылка на данные находящиеся в ХранилищеЗначений, а сами данные.

Решение

  • В свойствах табличного реквизита формы есть флаг "Использовать всегда". Если он установлен, то содержимое поля всегда передается между сервером и клиентом - например, при открытии формы. Этот флаг надо отключить, но при этом нужно учесть это в коде, так как по умолчанию значения этого поля на клиенте не будет. Пример можно посмотреть в 1С:Архив.

Ещё лучше использовать временное хранилище для передачи файлов между клиентом и сервером.

Печать (Ctrl+P)

16.3. Работа с двоичными данными

16.3.1. Общая информация

При реализации прикладных решений возможны ситуации, когда необходимо анализировать различные двоичные данные. Например, требуется по сигнатуре определить тип файла или выполнить какие-либо манипуляции с картинкой. Для работы с двоичными данными «1С:Предприятие» предоставляет специальные программные интерфейсы. Далее будут рассмотрены возможности по работе с двоичными данными.
Вся работа с двоичными данными базируется на понятии потока. Поток – это логическое обобщение произвольного (в общем случае) источника данных (объект Поток ). Система не предоставляет возможности создать самостоятельный объект Поток , который не связан с каким-либо источником. Но существуют производные объекты, которые можно создать – это поток, связанный с файлом на диске (объект ФайловыйПоток ) или поток, созданный в памяти (объект ПотокВПамяти ). Поток позволяет как читать данные, так и записывать их. Для определения возможности выполнения тех или иных операций, у потока (и производных объектов) существуют специальные методы, позволяющие определить, какие
операции доступны с данным потоком (методы ДоступнаЗапись() , ДоступноЧтение() , ДоступноИзменениеПозиции() ).
Если необходимо работать с потоком на более высоком уровне, в частности, выполнять чтение/запись таких данных, как число (разной разрядности) или строка, то для этого предназначены объекты ЧтениеДанных /ЗаписьДанных. С помощью этих объектов имеется возможность более структурировано подходить к двоичным данным, расположенным в потоке. Так, например, зная формат какого-либо файла, можно достаточно комфортно выполнять чтение такого файла, получая из заголовков нужные данные (которые, как правило, представлены типами число и строка), пропуская не нужные блоки данных и загружая для обработки нужные.
Общую схему работы с двоичными данными можно представить следующим образом:

  1. Выполняется получение потока
  2. Создается объект ЧтениеДанных или ЗаписьДанных .
  3. С помощью объекта, созданного в п.2, выполняются требуемые действия.
  4. Закрывается объект, созданный в п.2.
  5. Если никаких операций больше выполнять не требуется – закрывается поток, полученный в п.1.
  6. Если требуется продолжить работу с потоком, то можно выполнить установку новой позиции в потоке (если эта операция поддерживается) и продолжить работу, начиная с п.2.

Стоит отметить, что имеется возможность объединить пп.1 и 2. Другими словами, система предоставляет возможность создания объектов ЧтениеДанных/ЗаписьДанных сразу из, например, объекта ДвоичныеДанные .
Для выполнения различных операций с двоичными данными система предоставляет возможность получить некоторую часть потока в качестве обособленного фрагмента с произвольным (побайтовым) доступом (объект БуферДвоичныхДанных ). Размер буфера задается при создании и не может быть изменен в дальнейшем. При работе с буфером двоичных данных имеется возможность работать с числами разной разрядности как с
единым целым. При этом имеется возможность указания порядка следования байтов в словах: «младший-старший » (little endian ) или «старший-младший » (big endian ). Также имеется возможность разбиения одного буфера на несколько и объединения нескольких буферов двоичных данных в один результирующий буфер.
Важно отметить, что работа с буфером двоичных данных позволяет существенно упростить реализацию в том случае, если работа с двоичными данными реализуется на стороне клиентского приложения в асинхронном режиме. В этом случае чтение данных в буфер будет выполняться асинхронной операцией, а работа с данными буфера является синхронной.
Работа с двоичными данными доступна на стороне клиентского (включая веб-клиент) приложения и на стороне сервера, а также в синхронной и асинхронной схемах работы. Дальнейшие примеры будут использовать синхронную схему работы.

16.3.2. Чтение двоичных данных

В качестве примера чтения двоичных данных будет рассмотрена задача определения корректного формата файла, который выбрали в системе для дальнейшего использования. В роли проверяемого файла будет использоваться.wav-файл с аудио-данными. Для хранения.wav-файлов используется Resource Interchange File Format (RIFF), описание которого приведено по ссылке:

https://msdn.microsoft.com/enus/library/windows/desktop/ee415713.aspx (на английском языке). Для примера чтения будут использоваться следующие данные о формате:
1. первые 4 байта файла содержат идентификатор формата: RIFF.
2. следующие 4 байта содержат размер собственно аудио данных с порядком следования байт little-endian.
3. следующие 4 байта содержат текстовый тип используемых данных: WAVE.
Для выполнения этих действий потребуется следующий код на встроенном языке:

Чтение = Новый ЧтениеДанных(ИмяФайла, ПорядокБайтов.LittleEndian) ;
ФорматФайла = Чтение.ПрочитатьСимволы (4);
РазмерДанных = Чтение.ПрочитатьЦелое32 ();
ТипФайла = Чтение.ПрочитатьСимволы (4);
Если ФорматФайла <> “RIFF” Тогда
Сообщить(“Это не файл формата RIFF”);
Возврат ;
КонецЕсли ;
Если ТипФайла = “WAVE” Тогда
Сообщить (“Это WAV-файл с данными, размером ” + РазмерДанных + ” байт”);
Иначе
Сообщить (“Это не WAV-файл”);
Возврат;
КонецЕсли;

Рассмотрим пример более подробно.
Вначале открывается файл, имя которого содержится в переменной ИмяФайла, файл открывается для чтения (РежимОткрытияФайла.Открыть ), из файла будут только читать (ДоступКФайлу.Чтение ) и для чтения будет использоваться буфер размером 16 байт.
Затем формируется поток, предназначенный для чтения данных, который будет иметь порядок следования байтов «младший-старший» для данных типа Число. Затем из получившегося потока считывается 4 символа, 32-разрядное целое и еще 4 символа. Получившиеся данные анализируются и по результатам анализа принимается решение о том, является выбранный файл.wav-файлом или нет.

16.3.3. Запись двоичных данных

Запись двоичных данных в файл, в простейшем случае, выполняется следующим образом:

Запись = Новый ЗаписьДанных(ИмяФайла) ;
Для Индекс = 0 По 255 Цикл
Запись.ЗаписатьБайт(Индекс) ;
КонецЦикла;
Запись.Закрыть() ;

Данный пример выполняет запись в файл последовательности байтов от 0 до 255 (0xFF в 16-ричной системе). Это самый простой вариант записи.
Также можно использовать способ, аналогичный способу чтения, рассмотренному в предыдущем примере, когда получается файловый поток и в этот файловый поток выполняется запись данных.

16.3.4. Работа с буфером двоичных данных

Как уже было сказано выше, буфер двоичных данных предоставляет удобный способ по манипуляции фрагментами двоичных данных.
Поддерживается не только чтение данных, но и запись.
В качестве примера будет рассмотрен разбор заголовка RIFF-файла из примера чтения данных (см. здесь). Для построения примера будут использованы ровно та же информация о формате файла. Таким образом, необходимо прочитать из исходного файла буфер размером с заголовок файла. Заголовок состоит из трех 4-байтовых полей. Таким образом, необходимо прочитать 12 байт.

Буфер = Новый БуферДвоичныхДанных (12);
Файл = ФайловыеПотоки.Открыть(КаталогВременныхФайлов () + “Windows Logon.wav”, РежимОткрытияФайла.Открыть , ДоступКФайлу.Чтение );
Файл.Прочитать (Буфер , 0, 12);
Размер = Буфер.ПрочитатьЦелое32 (4);
ПотокСтроки = Новый ПотокВПамяти (Буфер );
ПотокСтроки.Перейти (0, ПозицияВПотоке.Начало );

ФорматФайла = ЧтениеСтроки.ПрочитатьСимволы (4, “windows-1251”);
ЧтениеСтроки.Закрыть ();
ПотокСтроки.Перейти (8, ПозицияВПотоке.Начало );
ЧтениеСтроки = Новый ЧтениеДанных (ПотокСтроки );
ТипФайла = ЧтениеСтроки.ПрочитатьСимволы( 4, “windows-1251”);
ЧтениеСтроки.Закрыть ();

Процесс получения данных в буфер двоичных данных не представляет из себя ничего особенного. Дальнейшие операции требуют некоторых комментариев. Чтение чисел любой поддерживаемой разрядности возможно из любой позиции буфера. В данном примере Буфер.ПрочитатьЦелое32(4) ; означает чтение 32-разрядного целого числа, начиная с 4 байта буфера. Таким образом, если требуется прочитать несколько чисел, расположенных в разных местах буфера, это можно сделать без прямого позиционирования в этом буфере.
Чтение строки, однако, не поддерживается буфером двоичных данных. Поэтому следует воспользоваться объектом, который это позволяет сделать: ЧтениеДанных . Объект ЧтениеДанных не может быть создан на основании буфера двоичных данных. Но на основании буфера двоичных данных можно создать поток, который является универсальным посредником между физическим местом хранения информации (файл, буфер двоичных данных) и высокоуровневым объектом, позволяющим работать с этими данными.
Когда создается объект ЧтениеДанных на основании какого-либо потока, он начинает читать данные с той позиции, которая в данный момент установлена в потоке. Поэтому в примере вначале происходит установка позиции в потоке, а потом создается объект ЧтениеДанных и выполняется чтение нужного количества символов. Подробное описание разницы между числом байтов и символов при чтении строк см. следующий раздел 16.3.5

16.3.5. Особенности использования

При использовании двоичных данных следует учитывать особенности работы с данными типа Строка . Особенность заключается в том, что длина строки, которую возвращает функция глобального контекста СтрДлина() , измеряется в символах. В символах же следует указывать размеры читаемых/записываемых данных в методах записи/чтения строк в объектах работы с двоичными данными (ПрочитатьСимволы() ,
ПрочитатьСтроку() , ЗаписатьСимволы(), ЗаписатьСтроку() ). При этом не существует однозначного варианта преобразования длины строки в символах в аналогичный параметр в байтах. В зависимости от содержимого строки и кодировки, это соотношение будет разным. Поэтому при работе с какими-либо структурами данных, в состав которых входят строки переменной длины, следует четко понимать, в каких единицах выражены длины строк.
Если в имеющихся данных длина строки указана в байтах, и строка указана в многобайтовой кодировке переменной длины (например, UTF-8), то с помощью объектов работы с двоичными данными, прочитать такую структуру из файла в данные типа Строка – в общем случае невозможно.
Зато в таком случае можно легко выполнять изменение позиции чтения/записи в файловом потоке. Если длина строки будет указана в символах, то появляется возможность считать такую строку в данные типа Строка, но становится невозможно выполнять изменение позиции чтения/записи в таком потоке.
Для получения длины строки в байтах, можно воспользоваться следующей функцией для преобразования строки в объект ДвоичныеДанные :

Функция ПолучитьДвоичныеДанныеИзСтроки (Знач СтрПараметр , Знач Кодировка = “UTF-8”)
ПотокПамять = Новый ПотокВПамяти ;
Писатель = Новый ЗаписьДанных(ПотокПамять) ;
Писатель.ЗаписатьСтроку (СтрПараметр , Кодировка );
Писатель.Закрыть ();
Возврат ПотокПамять.ЗакрытьИПолучитьДвоичныеДанные ();
КонецФункции

Собственно размер в байтах можно получить с помощью вызова функции Размер() у объекта ДвоичныеДанные, который получается в результате работы функции.
Не рекомендуется одновременное использование объектов ЧтениеДанных/ЗаписьДанных и потоковых объектов. Если между двумя последовательными операциями чтения из ЧтениеДанных или двумя последовательными операциями записи в ЗаписьДанных происходит изменение позиции в потоке, с которым работают объекты ЧтениеДанных/ЗаписьДанных – генерируется исключение. Так, следующий пример демонстрирует корректное изменение позиции в потоке при записи данных в поток:

Поток = Новый ПотокВПамяти ();

ЗаписьДанных.ЗаписатьСтроку (“Привет, мир!”);
ЗаписьДанных.Закрыть ();
Поток.Перейти (0, ПозицияВПотоке.Начало );
ЗаписьДанных = Новый ЗаписьДанных (Поток );
ЗаписьДанных.ЗаписатьСтроку (“Пока!”);
ЗаписьДанных.Закрыть ();
Следующий пример привет к возникновению исключения:

Поток = Новый ПотокВПамяти();

ЗаписьДанных.ЗаписатьСтроку(“Привет, мир!”);
Поток.Перейти(0, ПозицияВПотоке.Начало);
// В следующей строке будет сгенернировано исключение
ЗаписьДанных.ЗаписатьСтроку(“Пока!”);
В тоже время, возможны ситуации, когда поведение системы будет некорректно, но никаких ошибок формироваться не будет:

Поток = ПолучитьПоток();
ЧтениеДанных = Новый ЧтениеДанных(Поток);
ТестоваяСтрока = ЧтениеДанных.Прочитать();
ИсходнаяПозиция = Поток.ТекущаяПозиция();
ЗаписьДанных = Новый ЗаписьДанных(Поток);
ЗаписьДанных.ЗаписатьСтроку(“Неожиданная строка”);
ЗаписьДанных.Закрыть();
Поток.Перейти(ИсходнаяПозиция, ПозицияВПотоке.Начало);
// В общем случае невозможно определить, какое значение будет помещено в переменную ТестоваяСтрока2
ТестоваяСтрока2 = ЧтениеДанных.ПрочитатьСтроку();

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

Технологическая платформа 1С:Предприятие 8 позволяет сохранять в информационной базе произвольные файлы, получать их оттуда и использовать различными способами. Рассмотрим эти операции на примерах.

Перед выполнением загрузки файла в информационную базу 1С нужно получить полный адрес файла на диске. Работа с диалогами выбора файлов описана в .

Для хранения файлов используется реквизит (или ресурс регистра) с типом ХранилищеЗначения .

Загрузка произвольного файла в информационную базу 1С

Любой файл можно представить в виде двоичных данных и загрузить в ХранилищеЗначений .

При преобразовании двоичных данных в объект ХранилищеЗначения используется конструкция новый ХранилищеЗначения(Данные,Сжатие) с двумя параметрами:

  1. Данные — двоичные данные, которые нужно поместить в хранилище
  2. Сжатие — степень сжатия алгоритма Deflation. Целое число в диапазоне -1…9. -1 — степень сжатия по умолчанию. 0 — никакого сжатия, 9 — максимальная степень сжатия. Значение по умолчанию: -1. Параметр необязательный, если не указан, то сжатие не используется.

//Преобразуем файл в двоичные данные
Файл = Новый ДвоичныеДанные(Путь) ;

//Создаем новый объект ХранилищеЗначения

ХранилищеДанных = Новый ХранилищеЗначения(Файл, Новый СжатиеДанных(9 ) ) ;

Сохранение произвольного файла из информационной базы 1С на диск

Для сохранения файла из базы 1С на диск нужно определить путь и имя файла. Для этого существует диалог сохранения файлов, работа с которым описана в .

//Получаем двоичные данные из хранилища
//ХранилищеДанных - реквизит объекта с типом ХранилищеЗначения

//Записываем полученные данные на диск
//В переменной Путь находится полный адрес файла на диске
Данные. Записать(Путь) ;

Просмотр файла, находящегося в информационной базе 1С

Для просмотра сохраненного в базе файла необходимо, чтобы на компьютере было установлено приложение, открывающее данный файл.

//Получаем имя временного файла с необходимым расширением
//В переменную Расширение нужно поместить расширение файла, например "pdf"
Путь= ПолучитьИмяВременногоФайла(Расширение) ;

//Получаем данные из хранилища
//ХранилищеДанных - реквизит объекта с типом ХранилищеЗначения
Данные= ХранилищеДанных. Получить() ;

//Записываем данные во временный файл
Данные. Записать(Путь) ;

//Пытаемся открыть файл в предназначенном для него приложении
//Если приложение не найдено, появится системный диалог "Открыть с помощью..."
ЗапуститьПриложение(Путь) ;

Двоичные данные в 1С предназначены для хранения фалов произвольного формата. С их помощью можно:

  • Организовать взаимодействие по двоичному протоколу с различными устройствами;
  • Хранить в виде реквизита объекта метаданных файлы любых форматов;
  • Конвертировать текстовые данные в бинарные (чаще всего используется для отправки отчетов);
  • Работать с двоичными данными в памяти.

Что может система

При работе с двоичными данными платформа 8.3 умеет выполнять следующие действия:

  1. Выполнять чтение и запись двоичных данных;
  2. Перемещать данные с клиента на сервер и обратно с использованием временного хранилища;
  3. Инициализировать с помощью бинарных файлов объект типа «Картинка»;
  4. Считывать их из всемирной сети с использованием объектов «ПочтовоеВложение», «НТТРСоединение» и т.д.
  5. Использовать криптографические средства для шифрования и подписи важных вложений;
  6. При помощи объекта «ХешированиеДанных» вычислять хеш-функцию.

Сохранение данных в реквизит

Для примера создадим в тестовой конфигурации справочник.

На самом деле, использовать один и тот же справочник для хранения информации о номенклатуре и бинарных данных картинок немного неправильно. При достаточно больших объемах данных и тяжеловесных файлах крупного размера могут возникнуть нежелательные простои и «тормоза» в работе системы. Гораздо корректнее с точки зрения системы будет организовать отдельный справочник «Картинки», ссылку на который мы могли бы задать как тип реквизита.


Важно отметить, что ввиду того, что реквизиты типа «ХранилищеЗначения», содержащие двоичные данные недоступны в режиме управляемого приложения, обращение к ним возможно только с использованием метода РеквизитФормыВЗначение.


В поле сообщения представлена запись двоичных данных хранилища значений.

Чтение данных из реквизита

Создадим обработку, которая будет выводить хранящийся в бинарном виде в нашей конфигурации файл в табличный документ (это нужно, допустим для вывода на печать логотипа фирмы).


В принципе, это весь код, который нам нужен. С помощью оператора Получить() мы читаем двоичные данные, хранящиеся в соответствующем реквизите справочника и передаем их в объект «Картинка», который и будет показан в верхней левой ячейке табличного документа формы (Рис.9).

Рис.9

Преобразование данных

Нечасто, но бывает, что при работе с нестандартными обменами с внешними системами требуется конвертация данных из двоичного формата в формат Base64 или обратно.

В большинстве случаев платформа самостоятельно преобразует данные, если этого не происходит, необходимо воспользоваться глобальными функциями перевода:

  1. Base64Строка – переводит заданное значение в строку соответствующей кодировки;
  2. Base64Значение – делает обратное преобразование.

Оптимизация вышеприведенного кода

Код, представленный на Рис.4, безусловно, работает, но с одной существенной оговоркой: если в свойствах конфигурации установлен флажок «Режим использования модальности» (Рис.10). В противном случае его использование вызовет ошибку.
Рис.10

Для того, чтобы этого не происходило надо находясь в модуле формы элемента справочника, зайти в меню Текст->Рефакторинг->Нерекомендуемые синхронные вызовы->Преобразовать вызовы модуля.

По прошествии некоторого времени синхронные вызовы автоматически будут преобразованы в асинхронные, а код примет вид (Рис.11)

Рис.11