2009-10-31 13 views
24

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

Спасибо!

ответ

9

Не уверен, но, возможно, вам стоит исследовать около magic numbers.

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

+1

'FindMimeData' даже не обнаруживает что-то основное, как' audio/mp3', поэтому магические числа являются единственным вариантом, если вы обнаруживаете что-то вне этих 26 типов. Можете ли вы объяснить, почему вы считаете это ненадежным? – Mrchief

8

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

+3

В общем , вы не можете. Тем не менее, вы можете использовать эвристику для проверки магических чисел и с достаточной вероятностью угадать тип содержимого (как это делает команда 'file' в UNIX). Вы можете проверить его источник. –

+0

как я могу это сделать, Рэндольф? – AndreMiranda

+0

Вы можете подделать его с помощью Content.Net.Mail ContentType, отбросив загруженный файл в приложение (не сложно), или вы можете попробовать взломать URLMON.DLL из этого вопроса: http://stackoverflow.com/questions/58510/in-c-how-can-you-find-the-mime-type-of-a-file-on-the-file-signature-not-th – 2009-10-31 22:50:34

7

Короткий ответ: вы не можете

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

+0

Хорошим примером могут быть все типы файлов которые обертывают файлы zip/cab (т. е. .docx). Предположительно, если я могу просто изменить расширение и открыть файл с другой программой, тогда «магические числа» для базовых байтов файлов будут одинаковыми, что приведет к двусмысленности. – JoeBrockhaus

1

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

+0

как я могу это сделать? – AndreMiranda

+2

Как вы можете проверить, что расширение является тем, что находится в самом файле? то есть. PDF, хранящийся как JPG – user3308043

2

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

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

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

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

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

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

+0

Отличный ответ для краевых случаев. – user3308043

18

Как уже упоминалось, магия MIME - единственный способ сделать это. Многие платформы предоставляют обновленные и надежные магические файлы MIME и код, чтобы сделать это эффективно. Единственный способ сделать это в .NET без какого-либо стороннего кода - использовать с 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 вместе с загруженными файлами.Вы можете увидеть list of MIME types supported by urlmon.dll. Единственное, на что нужно обратить внимание, это image/pjpeg и image/x-png, которые являются нестандартными. В моем коде я заменяю их image/jpeg и image/png.

+0

Вы, по-видимому, ошибочны. Кто-то написал об этом здесь: http://webandlife.blogspot.com/2012/11/google-is-your-alcoholic-friend.html – SandRock

+3

Забавно, как его код перед рефакторингом точно такой же, как после рефакторинга. Не сулит ничего хорошего от кого-то, кто указывает на ошибки у других », но, по-видимому, не может справиться с копированием и вставкой самостоятельно. Какое-то вместилище в его правдоподобность? :) – Mrchief

+0

@Mrchielf: Это не то же самое. Первое различие, которое я нашел, заключалось в изменении 'uint' на' IntPtr'. Это имеет смысл, потому что почта была специально посвящена теме сопоставления типов данных C и C#. –

0

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

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

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

0

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

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

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

UPDATE: вы можете попробовать взглянуть на этот пост

Using .NET, how can you find the mime type of a file based on the file signature not the extension

0

Если вы знаете, что это System.Drawing.Image, вы можете сделать:

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; 
    } 
}