В практике разработчика 1С часто возникает ситуация, когда в общем макете хранятся двоичные данные, но их расширение (тип файла) заранее неизвестно или было утеряно. Поскольку платформа 1С позволяет хранить в макетах любые объекты — от простых текстовых документов до сложных исполняемых файлов — важно уметь программно определять, с чем именно мы имеем дело, чтобы корректно предложить пользователю программу для открытия или правильно обработать файл в коде.
В этой статье мы подробно разберем, как восстановить расширение файла, анализируя его внутреннее содержимое — так называемые сигнатуры или «магические числа» (magic numbers).
Большинство форматов файлов содержат в самом начале специфическую последовательность байтов, которая служит идентификатором типа данных. Анализ этих байтов является наиболее надежным способом определения расширения, так как он не зависит от имени файла. Например, файл формата PDF всегда начинается с определенной последовательности символов, независимо от того, как он назван. Для этой задачи есть автоматическое распознавание типа входящих файлов.
Для реализации проверки в 1С нам потребуется считать первые несколько байтов из объекта ДвоичныеДанные и сравнить их с эталонными значениями.
Рассмотрим по шагам, как написать универсальную функцию для определения расширения. Проанализируем использование объектов Поток и ЧтениеДанных, которые появились в платформе 8.3.9 и позволяют эффективно работать с двоичными потоками.
Ниже представлен пример кода, который считывает первые 8 байтов файла и сопоставляет их с популярными форматами (DOC, PDF, DOCX, ODT):
&НаСервере
Функция ОпределитьРасширениеФайлаПоСигнатуре(ДвоичныеДанныеМакета) Экспорт
Если ДвоичныеДанныеМакета = Неопределено Тогда
Возврат "";
КонецЕсли;
// Открываем поток для чтения двоичных данных
ПотокДанных = ДвоичныеДанныеМакета.ОткрытьПотокДляЧтения();
ЧтениеДанных = Новый ЧтениеДанных(ПотокДанных);
// Считываем первые 8 байт (этого достаточно для большинства форматов)
МассивБайтов = Новый Массив;
Попытка
Для Счетчик = 1 По 8 Цикл
МассивБайтов.Добавить(ЧтениеДанных.ПрочитатьБайт());
КонецЦикла;
Исключение
// Файл может быть слишком коротким
КонецПопытки;
ПотокДанных.Закрыть();
// Анализируем полученные байты
// Формат PDF: %PDF (в десятичном виде 37 80 68 70)
Если МассивБайтов[0] = 37 И МассивБайтов[1] = 80 И МассивБайтов[2] = 68 И МассивБайтов[3] = 70 Тогда
Возврат "pdf";
КонецЕсли;
// Старые форматы MS Office (DOC, XLS, PPT) начинаются с D0 CF 11 E0 A1 B1 1A E1
Если МассивБайтов[0] = 208 И МассивБайтов[1] = 207 И МассивБайтов[2] = 17 И МассивБайтов[3] = 224 Тогда
Возврат "doc"; // Или xls, в зависимости от контекста
КонецЕсли;
// Современные форматы (DOCX, XLSX, ODT) - это ZIP-архивы, сигнатура PK (80 75)
Если МассивБайтов[0] = 80 И МассивБайтов[1] = 75 И МассивБайтов[2] = 3 И МассивБайтов[3] = 4 Тогда
// Здесь нужна дополнительная проверка (разберем ниже)
Возврат "docx";
КонецЕсли;
Возврат "";
КонецФункции
Проанализируем сложную ситуацию: современные документы Microsoft Office и OpenOffice являются по сути ZIP-архивами. Все они начинаются с байтов 50 4B (символы PK). Если мы просто вернем «zip», это не поможет пользователю открыть документ в Word или Excel.
Чтобы точно определить подтип, нам нужно выполнить следующие действия:
.zip.ЧтениеZipФайла для анализа структуры архива.word/ — это docx.xl/ — это xlsx.mimetype с содержимым opendocument.text — это odt.Рассмотрим наиболее востребованные типы файлов и их байтовые последовательности (в HEX-формате и десятичном виде), которые вы можете добавить в свою функцию:
89 50 4E 47 0D 0A 1A 0A (Дес: 137 80 78 71 13 10 26 10).FF D8 FF (Дес: 255 216 255).42 4D (Символы BM).4D 5A (Символы MZ).37 7A BC AF 27 1C.52 61 72 21 1A 07.Выясним причину, почему для исполняемых файлов (EXE и DLL) используется одна и та же сигнатура. Это связано с тем, что оба типа используют формат PE (Portable Executable). В среде 1С такие файлы могут встречаться в макетах внешних компонент. Если вы обнаружили в начале 4D 5A, значит перед вами исполняемый код Windows.
Если ваша база 1С работает на операционной системе Windows, мы можем воспользоваться системными механизмами. В библиотеке urlmon.dll существует функция FindMimeFromData, которая умеет определять MIME-тип контента на основе анализа первых 256 байт.
Этот способ считается более надежным, так как Microsoft постоянно обновляет алгоритмы распознавания своих форматов. Вызвать эту функцию можно через создание внешней компоненты или через COM-объекты, если установлены соответствующие обертки. Однако стоит помнить, что этот метод привязывает ваше решение к платформе Windows и не будет работать на Linux-серверах.
В случае, если сервер 1С работает под управлением Linux, проанализируем другой эффективный подход. В Linux есть стандартная утилита file. Мы можем сохранить двоичные данные во временный файл и выполнить команду:
Команда = "file --mime-type -b " + ПутьКФайлу;
ЗапуститьПриложение(Команда, ...);
Эта утилита использует огромную базу данных сигнатур и выдаст вам точный MIME-тип (например, image/png), который легко преобразовать в расширение файла в коде 1С.
Чтобы в будущем не прибегать к анализу байтов, рекомендуется придерживаться следующих правил при разработке конфигураций:
РасширениеФайла) рядом с полем типа ХранилищеЗначения — для правильной архитектуры подойдёт перенос файлов из базы в тома.Резюмируя: если расширение все же потеряно, используйте объект ЧтениеДанных для анализа первых 4–8 байт. Этого достаточно для 90% случаев в корпоративном секторе. Для более сложных случаев с ZIP-контейнерами (Office 2007+) применяйте объект ЧтениеZipФайла.