使用.NET,如何根据文件签名而不是扩展名找到文件的mime类型

时间:2020-03-05 18:52:04  来源:igfitidea点击:

我正在寻找一种简单的方法来获取文件扩展名不正确或者未给出的mime类型,类似于仅在.Net中的此问题。

解决方案

回答

在Urlmon.dll中,有一个名为FindMimeFromData的函数。

从文档中

MIME type detection, or "data sniffing," refers to the process of determining an appropriate MIME type from binary data. The final result depends on a combination of server-supplied MIME type headers, file extension, and/or the data itself. Usually, only the first 256 bytes of data are significant.

因此,从文件中读取第一个(最多)256个字节,并将其传递给FindMimeFromData

回答

最后我确实使用了urlmon.dll。我以为会有一个更简单的方法,但这可行。我提供了可帮助其他人的代码,并在需要时允许我再次找到它。

using System.Runtime.InteropServices;

...

[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 static 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))
        {
            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";
        }
    }

回答

我们也可以在注册表中查找。

using System.IO;
    using Microsoft.Win32;

    string GetMimeType(FileInfo fileInfo)
    {
        string mimeType = "application/unknown";

        RegistryKey regKey = Registry.ClassesRoot.OpenSubKey(
            fileInfo.Extension.ToLower()
            );

        if(regKey != null)
        {
            object contentType = regKey.GetValue("Content Type");

            if(contentType != null)
                mimeType = contentType.ToString();
        }

        return mimeType;
    }

无论是从扩展名还是从幻数映射到MIME,我们都必须使用一种或者多种方式进入MIME数据库,而琐碎的Windows注册表就是这样一个地方。
对于平台独立的解决方案,尽管必须将该DB附带代码(或者作为独立库)。

回答

我认为正确的答案是史蒂夫·摩根(Steve Morgan)和塞尔吉(Serguei)的答案的结合。这就是Internet Explorer的工作方式。对FindMimeFromData的pinvoke调用仅适用于26种硬编码的mime类型。而且,即使可能存在更具体,更合适的mime类型,它也会给出模棱两可的mime类型(例如" text / plain"或者" application / octet-stream")。如果无法提供良好的mime类型,则可以转到注册表以获取更特定的mime类型。服务器注册表可能具有更多最新的mime类型。

请参阅:http://msdn.microsoft.com/en-us/library/ms775147(VS.85).aspx