【问题标题】:In C#, how can I know the file type from a byte[]?在 C# 中,如何从 byte[] 中知道文件类型?
【发布时间】:2010-12-11 21:48:42
【问题描述】:

我有一个从上传的文件填充的字节数组。但是,在代码的另一部分,我需要知道从 byte[] 上传的文件类型,以便将正确的内容类型呈现给浏览器!

谢谢!!

【问题讨论】:

    标签: asp.net-mvc c#-3.0 bytearray content-type


    【解决方案1】:

    如前所述,MIME 魔法是做到这一点的唯一方法。许多平台提供最新且强大的 MIME 魔术文件和代码以有效地执行此操作。在没有任何第三方代码的情况下在 .NET 中执行此操作的唯一方法是使用来自 urlmon.dll 的FindMimeFromData。方法如下:

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

    这使用 Internet Explorer MIME 检测器。这与 IE 用于发送 MIME 类型和上传文件的代码相同。你可以看到list of MIME types supported by urlmon.dll。需要注意的一件事是image/pjpegimage/x-png,它们是非标准的。在我的代码中,我将它们替换为 image/jpegimage/png

    【讨论】:

    • 你的外部方法声明似乎是错误的。有人在这里写过:webandlife.blogspot.com/2012/11/…
    • 有趣的是,重构前的代码与重构后的代码完全相同。对于那些在别人身上指出错误但显然不能自己处理复制/粘贴的人来说,这不是好兆头。有点损害他的信誉,不是吗? :)
    • @Mrchielf:不一样。我发现的第一个区别是将uint 更改为IntPtr。这是有道理的,因为这篇文章专门讨论了匹配 C 和 C# 数据类型的主题。
    【解决方案2】:

    不确定,但也许您应该调查一下magic numbers

    更新: 读了一遍,我认为它不是很可靠。

    【讨论】:

    • FindMimeData 甚至没有检测到像audio/mp3 这样基本的东西,所以如果你检测到这 26 种类型之外的东西,幻数是唯一的选择。你能详细说明为什么你认为它不可靠吗?
    【解决方案3】:

    您无法从字节流中知道它,但您可以在最初填充 byte[] 时存储 MIME 类型。

    【讨论】:

    • 一般来说,你不能。但是,您可以使用启发式方法来检查幻数并以很高的概率猜测内容类型(就像 UNIX 中的 file 命令所做的那样)。你可以查看它的来源。
    • 您可以使用 System.Net.Mail 的 ContentType 伪造它,方法是将您上传的文件转换为附件(不难),或者您可以从这个问题尝试 URLMON.DLL hack:@987654321 @
    【解决方案4】:

    如果你知道这是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;
       }
    }
    

    【讨论】:

    • 文件不是图片时这个函数返回什么?
    • 我很确定第二个 using 会引发异常。
    【解决方案5】:

    简短的回答:你不能

    更长的答案:通常,程序使用文件扩展名来了解它们正在处理的文件类型。如果您没有该扩展名,则只能进行猜测...例如,您可以查看前几个字节并检查您是否识别出众所周知的标头(例如 XML 声明标记,或位图或 JPEG 标头)。但这最终总是一个猜测:没有一些元数据或有关内容的信息,字节数组就毫无意义......

    【讨论】:

    • 一个很好的例子可能是包装 zip/cab 文件的所有文件类型(即 .docx)。据推测,如果我能够简单地更改扩展名并使用另一个程序打开文件,那么底层文件字节的“幻数”将是相同的,从而导致歧义。
    【解决方案6】:

    如果您知道文件名的扩展名,那么 System.Web.MimeMapping 可能会解决问题:

    MimeMapping.GetMimeMapping(fileDisplayNameWithExtension)
    

    我在 MVC Action 中这样使用它:

    return File(fileDataByteArray, MimeMapping.GetMimeMapping(fileDisplayNameWithExtension), fileDisplayNameWithExtension);
    

    【讨论】:

      【解决方案7】:

      让我想起了我们,呃,“某些人”过去在早期的免费图片托管网站上共享 50MB 的 rar 文件,只需将 .gif 扩展名添加到 .rar 文件名。

      很明显,如果您是面向公众的并且您期望某种文件类型,并且您必须确保它是该文件类型,那么您就不能只信任扩展名。

      另一方面,如果您的应用没有理由不信任上传的扩展名和/或 MIME 类型,那么只需在文件上传时获取这些内容,就像您从 @rossfabircant 和 @RandolphPotter 收到的答案一样。创建一个具有 byte[] 以及原始扩展名或 mimetype 的类型,然后传递它。

      如果您需要验证文件实际上是某种预期类型,例如有效的 .jpeg 或 .png,您可以尝试将文件解释为这些类型并查看它是否成功打开。 (System.Drawing.Imaging.ImageFormat)

      如果您尝试仅从二进制内容中对文件进行分类,并且它可能是整个世界中的任何格式,这确实是一个棘手的开放式问题,并且没有 100% 可靠的方法来做到这一点.您可以针对它调用TrID,如果您能找到(并负担得起)它们,执法调查人员可能会使用类似的取证工具。

      如果您不必以艰难的方式去做,请不要这样做。

      【讨论】:

      • 边缘情况的绝佳答案。
      【解决方案8】:

      你不想那样做。上传文件时调用 Path.GetExtension,并使用 byte[] 传递扩展名。

      【讨论】:

      • 如何验证扩展名是文件本身的内容? IE。以 JPG 格式存储的 PDF
      【解决方案9】:

      如果您希望支持的预期文件类型数量有限,则可以使用幻数。

      一个简单的检查方法是使用文本/十六进制编辑器打开示例文件,并研究前导字节,看看是否有一些东西可以用来区分/丢弃受支持集合中的文件。

      另一方面,如果您希望识别任意文件类型,是的,正如大家已经说过的那样,很难。

      【讨论】:

        【解决方案10】:

        使用 System.Drawing.Image 'RawFormat.Guid' 属性,您可以检测图像的 MIME 类型。

        但我不确定如何找到其他文件类型。

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

        更新:你可以试试看这篇文章

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

        【讨论】:

          猜你喜欢
          • 2012-09-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-02-18
          • 2014-05-10
          • 2018-03-25
          • 1970-01-01
          • 2013-03-19
          相关资源
          最近更新 更多