Как в C # узнать тип файла по байту []?

У меня есть массив байтов, заполненный из загруженного файла. Но в другой части кода мне нужно знать этот тип файла, загруженного из байта [], чтобы я мог отображать правильный тип содержимого в браузере!

Спасибо!!


person André Miranda    schedule 31.10.2009    source источник


Ответы (10)


Не уверен, но, возможно, вам стоит узнать о магических числах.

Обновление: Читая об этом, я не думаю, что это очень надежно.

person Carles Company    schedule 31.10.2009
comment
FindMimeData даже не обнаруживает чего-то столь же простого, как audio/mp3, поэтому магические числа - единственный вариант, если вы обнаруживаете что-то за пределами этих 26 типов. Не могли бы вы объяснить, почему вы считаете его ненадежным? - person Mrchief; 01.08.2014

Как уже упоминалось, магия MIME - единственный способ сделать это. Многие платформы предоставляют обновленные и надежные волшебные файлы MIME и код, чтобы делать это эффективно. Единственный способ сделать это в .NET без стороннего кода - использовать FindMimeFromData из urlmon.dll. Вот как:

public static int MimeSampleSize = 256;

public static string DefaultMimeType = "application/octet-stream";

[DllImport(@"urlmon.dll", CharSet = CharSet.Auto)]
private extern static uint FindMimeFromData(
    uint pBC,
    [MarshalAs(UnmanagedType.LPStr)] string pwzUrl,
    [MarshalAs(UnmanagedType.LPArray)] byte[] pBuffer,
    uint cbSize,
    [MarshalAs(UnmanagedType.LPStr)] string pwzMimeProposed,
    uint dwMimeFlags,
    out uint ppwzMimeOut,
    uint dwReserverd
);

public static string GetMimeFromBytes(byte[] data) {
    try {
        uint mimeType;
        FindMimeFromData(0, null, data, (uint)MimeSampleSize, null, 0, out mimeType, 0);

        var mimePointer = new IntPtr(mimeType);
        var mime = Marshal.PtrToStringUni(mimePointer);
        Marshal.FreeCoTaskMem(mimePointer);

        return mime ?? DefaultMimeType;
    }
    catch {
        return DefaultMimeType;
    }
}

При этом используется детектор MIME Internet Explorer. Это тот же код, который используется IE для отправки типа MIME вместе с загруженными файлами. Вы можете увидеть список типов MIME, поддерживаемых urlmon .dll. Следует остерегаться image/pjpeg и image/x-png, которые нестандартны. В моем коде я заменяю их на image/jpeg и image/png.

person mroach    schedule 31.03.2011
comment
Объявление внешнего метода кажется неправильным. Кто-то написал об этом здесь: webandlife.blogspot.com/ 2012/11 / - person SandRock; 22.07.2013
comment
Забавно, что его код до рефакторинга точно такой же, как после рефакторинга. Не сулит ничего хорошего тем, кто указывает на ошибки других, но, очевидно, не может справиться с копированием / вставкой самостоятельно. Как бы то ни было, подрывает его авторитет, не так ли? :) - person Mrchief; 01.08.2014
comment
@Mrchielf: Это не то же самое. Первое различие, которое я обнаружил, заключалось в изменении uint на IntPtr. Это имеет смысл, потому что сообщение было специально посвящено теме сопоставления типов данных C и C #. - person Ben Voigt; 08.12.2017

Вы не можете узнать его из байтового потока, но вы можете сохранить тип MIME при первоначальном заполнении byte[].

person Community    schedule 31.10.2009
comment
В общем, нельзя. Однако вы можете использовать эвристику для проверки магических чисел и определения типа содержимого с хорошей вероятностью (как это делает команда file в UNIX). Вы можете проверить его источник. - person mmx; 31.10.2009
comment
Вы можете подделать его с помощью ContentType System.Net.Mail, преобразовав загруженный файл во вложение (это несложно), или вы можете попробовать взлом URLMON.DLL из этого вопроса: stackoverflow.com/questions/58510/ - person ; 01.11.2009

Короткий ответ: нельзя

Более длинный ответ: обычно программы используют расширение файла, чтобы знать, с каким типом файла они имеют дело. Если у вас нет этого расширения, вы можете только догадываться ... например, вы можете посмотреть на первые несколько байтов и проверить, распознаете ли вы хорошо известный заголовок (например, тег объявления XML или растровое изображение или заголовок JPEG ). Но в конце концов это всегда будет предположением: без каких-либо метаданных или информации о содержимом массив байтов просто бессмысленен ...

person Thomas Levesque    schedule 31.10.2009
comment
Хорошим примером могут быть все типы файлов, в которые помещаются файлы zip / cab (например, .docx). Предположительно, если я могу просто изменить расширение и открыть файл с помощью другой программы, тогда «магические числа» для байтов базового файла будут такими же, что приведет к двусмысленности. - person JoeBrockhaus; 04.12.2014

Если вы знаете, что это _1 _, вы можете:

public static string GeMimeTypeFromImageByteArray(byte[] byteArray)
{
   using (MemoryStream stream = new MemoryStream(byteArray))
   using (Image image = Image.FromStream(stream))
   {
       return ImageCodecInfo.GetImageEncoders().First(codec => codec.FormatID == image.RawFormat.Guid).MimeType;
   }
}
person yazanpro    schedule 08.12.2017
comment
Что возвращает эта функция, если файл не является изображением? - person Christian; 07.03.2019
comment
Я почти уверен, что на втором using возникнет исключение. - person yazanpro; 25.03.2019

Если вы знаете расширение имени файла, это может быть System.Web.MimeMapping:

MimeMapping.GetMimeMapping(fileDisplayNameWithExtension)

Я использовал его в MVC Action вот так:

return File(fileDataByteArray, MimeMapping.GetMimeMapping(fileDisplayNameWithExtension), fileDisplayNameWithExtension);
person Yasser Sobhdel    schedule 08.08.2018

Напоминает мне о тех днях, когда мы, эээээ, "некоторые люди" использовали rar-файлы размером 50 МБ на ранних сайтах бесплатного хостинга изображений, просто добавляя расширение .gif к имени файла .rar.

Очевидно, что если вы общедоступны и ожидаете определенный тип файла, и вы должны быть уверены, что это именно этот тип файла, то вы не можете просто доверять расширению.

С другой стороны, если у вашего приложения не будет причин не доверять загруженному расширению и / или типу MIME, тогда просто получите их, когда файл будет загружен, как ответы, полученные от @rossfabircant и @RandolphPotter. создайте тип, который имеет byte [], а также исходное расширение или mimetype, и передайте его.

Если вам нужно убедиться, что файл действительно является определенным ожидаемым типом, например допустимым .jpeg или .png, вы можете попробовать интерпретировать файл как эти типы и посмотреть, успешно ли он открывается. (System.Drawing.Imaging.ImageFormat)

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

Если вам не нужно делать это жестко, не делайте этого.

person DanO    schedule 04.11.2009
comment
Отличный ответ для крайних случаев. - person user3308043; 25.07.2014

Вы не хотите так поступать. Вызовите Path.GetExtension при загрузке файла и передайте расширение с байтом [].

person RossFabricant    schedule 31.10.2009
comment
Как вы можете убедиться, что расширение - это то, что находится в самом файле? т.е. PDF-файл в формате JPG - person user3308043; 25.07.2014

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

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

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

person Oskuro    schedule 20.06.2012

Используя свойство System.Drawing.Image RawFormat.Guid, вы можете определить MIME-тип изображений.

но я не уверен, как найти другие типы файлов.

http://www.java2s.com/Code/CSharp/Network/GetImageMimeType.htm

ОБНОВЛЕНИЕ: вы можете попробовать взглянуть на это сообщение

Используя .NET, как найти MIME-тип файла на основе подписи файла, а не расширения?

person Muhammad Omar ElShourbagy    schedule 25.02.2013