В данной статье рассмотрим применение новых методов платформы 8.3.9 по работе с двоичными данными. Сначала немного теории.
Как было раньше
Ранее 1С предоставляла для работы с двоичными данными одноименный тип и некоторые методы работы с файлами. Думаю, многим известна ситуация, когда для отправки файла в формате multipart/form-data использовался метод «ОбъединитьФайлы». Это было связано с отсутствием методов по работе с внутренним содержимым двоичных данных.
Что нового
В версии 8.3.9 эта ситуация меняется. Разработчики платформы предоставили в наше распоряжение несколько новых типов и методов. Основным из них является обобщенный объект Поток. Потоков бывает три типа: Поток, ФайловыйПоток и ПотокВПамяти.

Основным преимуществом потоков является их способность работать с данными произвольного объема. Но в то же время они предоставляют ограниченные возможности.
Для получения расширенных возможностей необходимо на основе потока создать объект ЧтениеДанных. С помощью него можно читать отдельные байты, символы, числа.
Побайтовые операции
Для анализа работы новых методов возьмем  за пример анализ параметров изображений для загрузки через API ВКонтакте.
Требования для загрузки фото в товар группы:
Ограничения: минимальный размер фото — 200x200px, сумма высоты и ширины не более 14000px, файл объемом не более 50 МБ.
Внимание! Формат файла JPG не обрабатывается в обработке.
Вес файла
Сначала на основе выбранного файла создадим ФайловыйПоток и сможем сразу получить Размер файла в байтах:
ПотокИсходный = ФайловыеПотоки.ОткрытьДляЧтения(Объект.ИмяФайла);
///1. Размер файла
Объект.РазмерФайла = Строка(ПотокИсходный.Размер() / 1024) + " Кб";
Формат файла
 Каждый формат файла отличается друг от друга внутренней структурой. Отличительными особенностями каждого формата будем называть сигнатурами.
Зададим сигнатуры для каждого формата:
///Зададим сигнатуры нужных форматов 
МассивДопустимыхФорматов = Новый Соответствие;
МассивДопустимыхФорматов.Вставить("PNG", 	РазложитьСтрокуВМассивПодстрок("137,80,78,71,13,10,26,10"));
//МассивДопустимыхФорматов.Вставить("JPEG", 	РазложитьСтрокуВМассивПодстрок("255,216"));
МассивДопустимыхФорматов.Вставить("GIF1", 	РазложитьСтрокуВМассивПодстрок("71,73,70,56,57,97"));
МассивДопустимыхФорматов.Вставить("BMP", 	РазложитьСтрокуВМассивПодстрок("66,77"));
МассивДопустимыхФорматов.Вставить("TIF", 	РазложитьСтрокуВМассивПодстрок("73,73,42,0"));
МассивДопустимыхФорматов.Вставить("TIF1", 	РазложитьСтрокуВМассивПодстрок("77,77,0,42"));
Каким образом получены сигнатуры?
В hex-записи сигнатура PNG файла выглядит так и состоит из 8 байт:
89 50 4E 47 0D 0A 1A 0A
Это можно проверить, открыв любой PNG файл в HEX-редакторе. Например, возьмем иконку месседжера Telegram размером 32*32.


Переведем эти значения из 16-ной системы в 10-ную и получим значения:
"137,80,78,71,13,10,26,10"
Аналогично поступаем с остальными форматами.
Проверяем формат файла
ЧтениеДанных = Новый ЧтениеДанных(ПотокИсходный, КодировкаТекста.ANSI, ПорядокБайтов.BigEndian);
ИскомыйТипФайла = ПроверитьСоответствиеТипаФайла(ЧтениеДанных, МассивДопустимыхФорматов);
	
	Если ИскомыйТипФайла = Неопределено Тогда
		Сообщить("Не поддерживаемый тип файла");
		Возврат;
	КонецЕсли;
&НаСервере
Функция ПроверитьСоответствиеТипаФайла(ЧтениеДанных, МассивДопустимыхФорматов)
	
	МаксРазмер = 0;
	Для Каждого ТипФайла Из МассивДопустимыхФорматов Цикл
		МаксРазмер = Макс(МаксРазмер, ТипФайла.Значение.Количество());		
	КонецЦикла; 
	
	//прочитаем в новый буфер максимальный размер сигнатуры
	БуферПроверка = ЧтениеДанных.ПрочитатьВБуферДвоичныхДанных(МаксРазмер);
	
	Для Каждого ТипФайла Из МассивДопустимыхФорматов Цикл
		//Хотелось бы конечно напрямую сравнить Буфер = Буфер, но так не работает
		//Приходится сравнивать каждый байт
		
		ДвоичнаяСигнатураФормата = ПолучитьСигнатуруФорматаВДвоичномВиде(ТипФайла.Значение);
		БуферПроверкаТипаФайла = БуферПроверка.Прочитать(0, ДвоичнаяСигнатураФормата.Размер);
		
		Сч = 0;
		Равны = Истина;
		Для Каждого Счет Из БуферПроверкаТипаФайла Цикл
			Если Счет <> ДвоичнаяСигнатураФормата[Сч] Тогда
				Равны = Ложь;	
				Прервать;
			КонецЕсли; 
		    Сч = Сч + 1; 
		КонецЦикла; 
		Если Равны Тогда
			Возврат ТипФайла.Ключ;
		КонецЕсли; 
	КонецЦикла; 
	Возврат НЕопределено;
КонецФункции
Т.к. буферы нельзя сравнить между собой, пришлось сравнивать байт за байтом. Если кто знает, как сделать красивее, пишите в комментариях.
Ищем размеры изображения
ЧтениеДанных.ПропуститьДо("IHDR", КодировкаТекста.ANSI);
Так же из спецификации формата PNG известно, что ширина и высота изображения занимают по 4 байта. Сначала прочитаем все 8 байтов, а потом отдельно ширину и высоту:
БуферЗаголовок 				= ЧтениеДанных.ПрочитатьВБуферДвоичныхДанных(8);
ОБъект.ШиринаИзображения 	= БуферЗаголовок.Прочитать(0, 4).ПрочитатьЦелое32(0, ПорядокБайтов.BigEndian);
Объект.ВысотаИзображения 	= БуферЗаголовок.Прочитать(4, 4).ПрочитатьЦелое32(0, ПорядокБайтов.BigEndian);
В методе ПрочитатьВБуферДвоичныхДанных() мы указываем общее количество байтов, которое хотим прочитать в буфер двоичных данных. Далее этот буфер читаем методом Прочитать(0, 4) – где 0 это позиция, а 4 – количество байтов для чтения.
Если мы продолжим читать этот экземпляр, то не сможем найти размеры изображения. Поэтому используем метод потока Перейти() и создаем новое ЧтениеДанных на основе нашего исходного потока. Дальше как обычно читаем размеры.

ТекПозиция 		= ПотокИсходный.ТекущаяПозиция();
ПотокИсходный.Перейти(-ТекПозиция, ПозицияВПотоке.Текущая);
ЧтениеДанныхGIF = Новый ЧтениеДанных(ПотокИсходный, КодировкаТекста.ANSI, ПорядокБайтов.LittleEndian);
БуферРазмеры 				= ЧтениеДанныхGIF.ПрочитатьВБуферДвоичныхДанных(10);
Объект.ШиринаИзображения 	= БуферРазмеры.Прочитать(6,2).ПрочитатьЦелое16(0, ПорядокБайтов.LittleEndian);
Объект.ВысотаИзображения 	= БуферРазмеры.Прочитать(8,2).ПрочитатьЦелое16(0, ПорядокБайтов.LittleEndian);
Таким образом, зная спецификации нужных форматов, мы проверяем формат файла, размеры изображения.
Отправка изображения через API ВКонтакте
Привожу пример работающего кода отправки сообщения multipart/form-data (проверено на отправке фото товара в группу ВКонтакте) (в обработке не приведен этот код):
//здесь получается объект с типом Картинка
Изображение = Номенклатура.ОсновноеИзображение.Хранилище.Получить();
//в функцию передаем двоичные данные картинки стандартным методом ПолучитьДвоичныеДанные()
ДвоичныеДанныеТело = СобратьИзображениеИзДвоичныхДанных(Изображение.ПолучитьДвоичныеДанные(), Boundary, ИмяФайлаДляЗагрузки);
Функция СобратьИзображениеИзДвоичныхДанных(ДвоичныеДанныеИзображения, Boundary, ИмяФайлаДляЗагрузки)
	
	ПотокТело = Новый ПотокВПамяти();
	ЗаписьДанных = Новый ЗаписьДанных(ПотокТело);
	
	ЗаписьДанных.ЗаписатьСтроку("--" + Boundary);
	ЗаписьДанных.ЗаписатьСтроку("Content-Disposition: form-data; name=""file""; filename=""" + ИмяФайлаДляЗагрузки + """");	
	
	ЗаписьДанных.ЗаписатьСтроку("Content-Type: image/jpeg");
	ЗаписьДанных.ЗаписатьСтроку("");
	ЗаписьДанных.Записать(ДвоичныеДанныеИзображения);		
	//Завершение раздела двоичных данных
	ЗаписьДанных.ЗаписатьСтроку("--" + Boundary);
	
	//Завершение сообщения для сервера
	ЗаписьДанных.ЗаписатьСтроку("--" + Boundary + "--");	
	
	ЗаписьДанных.Закрыть();
	
	ДвоичныеДанныеТело = ПотокТело.ЗакрытьИПолучитьДвоичныеДанные();
	
	Возврат ДвоичныеДанныеТело;
	
	
КонецФункции      
 
			Готовое решение
ККТ-ОНЛАЙН 54-ФЗ: Обработка для работы онлайн касс АТОЛ, ШТРИХ, VIKI PRINT и т.д. МАРКИРОВКА (Разрешит. режим) + ЭКВАЙРИНГ + БЕСПЛАТНЫЙ ДЕМО
Универсальная обработка для фискальных регистраторов! Подключайте любые ККТ, включая Веб сервер АТОЛ, без обновления 1С и работайте с несколькими кассами одновременно. Тестовый доступ — бесплатно!
Вступайте в нашу телеграмм-группу Инфостарт
 
                                 
                                 
                                     
                                     
                                     
                                    