2013-03-08 89 views
6

FindMimeFromData方法通过Windows DLL Urlmon.dll能够确定MIME类型存储在存储器中的给定的数据,考虑第一256个字节的字节阵列的专用FindMimeFromData方法,这些数据被存储在哪里。替代在Urlmon.dll中一个具有多个MIME类型

然而,在阅读文档后,我被导到MIME Type Detection in Windows Internet Explorer,我可以找到这种方法能够识别的MIME类型。请参阅list。如您所见,此方法仅限于26种MIME类型。

所以我想知道是否有人可以指向另一种方法与更多的MIME类型,或者另一种方法/类我可以包括我认为适合的MIME类型。

谢谢。

+0

我不知道这是你想要的,但你可以从主要的MIME类型的列表IIS。 – din 2013-03-08 18:27:29

+0

但是FindMimeFromData方法被硬编码为26种MIME类型,我无法修改它接受更多的MIME类型。 – 2013-03-08 18:36:21

+0

那么在那种情况下,你可能会找到另一种方式来完成你的任务。如果你能找到你想要读取的数据类型的“扩展名”,那么你可能有更多的机会来确定MIME类型,如果你只是想从读取二进制数据知道MIME类型,那么就我所知,你必须限制为FindMimeFromData方法。 – din 2013-03-08 18:44:33

回答

13

所以我想知道如果任何人都可以点我的另一种方法与 更多的MIME类型,或者另一种方法/类是你,我 可以包括MIME类型,我认为合适的。

我用Winista和URLMON的混合检测上传的文件的 real格式..

下载Winista:http://www.netomatix.com/Products/DocumentManagement/MimeDetector.aspx

或者与URLMON下载该项目依傍在这里: https://github.com/MeaningOfLights/MimeDetect

Winista MIME检测

说有人用jpg扩展名重命名exe文件,你仍然可以使用二进制分析来确定“真实”文件格式。它不会检测到swf或flv,但几乎可以完成其他众所周知的格式+您可以使用十六进制编辑器并添加更多可检测的文件。

文件魔术

Winista检测使用包含有关文件类型的信息和用于标识内容type.eg签名的XML文件“的mime-type.xml”真正的MIME类型:

<!-- 
! Audio primary type 
! --> 

<mime-type name="audio/basic" 
      description="uLaw/AU Audio File"> 
    <ext>au</ext><ext>snd</ext> 
    <magic offset="0" type="byte" value="2e736e64000000"/> 
</mime-type> 

<mime-type name="audio/midi" 
      description="Musical Instrument Digital Interface MIDI-sequention Sound"> 
    <ext>mid</ext><ext>midi</ext><ext>kar</ext> 
    <magic offset="0" value="MThd"/> 
</mime-type> 

<mime-type name="audio/mpeg" 
      description="MPEG Audio Stream, Layer III"> 
    <ext>mp3</ext><ext>mp2</ext><ext>mpga</ext> 
    <magic offset="0" value="ID3"/> 
</mime-type> 

当Winista失败的检测到真正的文件格式,我已经使出回URLMON方法:

public class urlmonMimeDetect 
{ 
    [DllImport(@"urlmon.dll", CharSet = CharSet.Auto)] 
    private extern static System.UInt32 FindMimeFromData(
     System.UInt32 pBC, 
     [MarshalAs(UnmanagedType.LPStr)] System.String pwzUrl, 
     [MarshalAs(UnmanagedType.LPArray)] byte[] pBuffer, 
     System.UInt32 cbSize, 
     [MarshalAs(UnmanagedType.LPStr)] System.String pwzMimeProposed, 
     System.UInt32 dwMimeFlags, 
     out System.UInt32 ppwzMimeOut, 
     System.UInt32 dwReserverd 
    ); 

public string GetMimeFromFile(string filename) 
{ 
    if (!File.Exists(filename)) 
     throw new FileNotFoundException(filename + " not found"); 

    byte[] buffer = new byte[256]; 
    using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) 
    { 
     if (fs.Length >= 256) 
      fs.Read(buffer, 0, 256); 
     else 
      fs.Read(buffer, 0, (int)fs.Length); 
    } 
    try 
    { 
     System.UInt32 mimetype; 
     FindMimeFromData(0, null, buffer, 256, null, 0, out mimetype, 0); 
     System.IntPtr mimeTypePtr = new IntPtr(mimetype); 
     string mime = Marshal.PtrToStringUni(mimeTypePtr); 
     Marshal.FreeCoTaskMem(mimeTypePtr); 
     return mime; 
    } 
    catch (Exception e) 
    { 
     return "unknown/unknown"; 
    } 
} 
} 

从Winista方法中,我退到这里的URLMON:

public MimeType GetMimeTypeFromFile(string filePath) 
    { 
     sbyte[] fileData = null; 
     using (FileStream srcFile = new FileStream(filePath, FileMode.Open, FileAccess.Read)) 
     { 
      byte[] data = new byte[srcFile.Length]; 
      srcFile.Read(data, 0, (Int32)srcFile.Length); 
      fileData = Winista.Mime.SupportUtil.ToSByteArray(data); 
     } 

     MimeType oMimeType = GetMimeType(fileData); 
     if (oMimeType != null) return oMimeType; 

     //We haven't found the file using Magic (eg a text/plain file) 
     //so instead use URLMon to try and get the files format 
     Winista.MimeDetect.URLMONMimeDetect.urlmonMimeDetect urlmonMimeDetect = new Winista.MimeDetect.URLMONMimeDetect.urlmonMimeDetect(); 
     string urlmonMimeType = urlmonMimeDetect.GetMimeFromFile(filePath); 
     if (!string.IsNullOrEmpty(urlmonMimeType)) 
     { 
      foreach (MimeType mimeType in types) 
      { 
       if (mimeType.Name == urlmonMimeType) 
       { 
        return mimeType; 
       } 
      } 
     } 

     return oMimeType; 
    } 

Winista from netomatix。 AFAIK是在2000年初基于开源Java项目进行C#重写的。请享用!

你也可以使用注册表方法或中提到的.Net 4.5 method由Paul Zahra链接,但Winista是最好的恕我直言。

UPDATE:

对于桌面应用程序,你可能会发现WindowsAPICodePack效果更好:

using Microsoft.WindowsAPICodePack.Shell; 
using Microsoft.WindowsAPICodePack.Shell.PropertySystem; 

private static string GetFilePropertyItemTypeTextValueFromShellFile(string filePathWithExtension) 
{ 
    var shellFile = ShellFile.FromFilePath(filePathWithExtension); 
    var prop = shellFile.Properties.GetProperty(PItemTypeTextCanonical); 
    return prop.FormatForDisplay(PropertyDescriptionFormatOptions.None); 
} 
+0

谢谢杰里米。我喜欢你的答案,但是当涉及到依赖Urlmon.dll中的FindMimeFromData方法时,我会非常小心,因为我已经阅读(如果我没记错的话),它可能会返回不正确的MIME类型,如果适当的MIME类型不适用,在Windows注册表中某些特定位置定义了这些值,而且这些值也可能被篡改,这在向最终用户交付时会出现问题。考虑到这一点,我只能依靠类似于你用* Winista *展示的检测方法,你在你的答案中显示... – 2013-03-25 01:53:24

+1

...现在想...也许我也可以将一个小型控制台应用程序放在一起,谁会通过我自己制作的大量文件使用正确的扩展名(以及已知的MIME)进行嗅探,并搜索相同扩展名的每个文件的前256个字节的相似性。这样我可以建立一个MIME类型的大小列表。那么我的业余时间。谢谢杰里米。 – 2013-03-25 01:58:05

+0

尝试了最后一个GetFilePropertyItemTypeTextValueFromShellFile,在我的情况下它总是返回一个'File'类型,从来没有我想要的(如Microsoft Word文档),如果文件路径有扩展名 - 那么我得到期望的结果 - 但是没有扩展名,这是无用 – Nutshell 2014-10-15 01:00:02

2

有多种可能的解决方案in this SO post这将至少给你一些思考的食物。

似乎唯一真正的方法是用二进制读取它,然后进行比较,无论MIME类型是以某种方式声明硬编码还是依赖于机器自己的可用MIME类型/注册表。

+1

+1感谢您的链接,发布到它的答案http://stackoverflow.com/a/13614746/114298应该证明在我决定构建自己的FindMineFromData替代方案时很有用。 – 2013-03-18 19:58:01

+0

+1运动精神 - 看到我的答案为二进制方法:) – 2013-03-24 05:54:11