【发布时间】:2010-12-11 21:48:42
【问题描述】:
我有一个从上传的文件填充的字节数组。但是,在代码的另一部分,我需要知道从 byte[] 上传的文件类型,以便将正确的内容类型呈现给浏览器!
谢谢!!
【问题讨论】:
标签: asp.net-mvc c#-3.0 bytearray content-type
我有一个从上传的文件填充的字节数组。但是,在代码的另一部分,我需要知道从 byte[] 上传的文件类型,以便将正确的内容类型呈现给浏览器!
谢谢!!
【问题讨论】:
标签: asp.net-mvc c#-3.0 bytearray content-type
如前所述,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/pjpeg 和image/x-png,它们是非标准的。在我的代码中,我将它们替换为 image/jpeg 和 image/png。
【讨论】:
uint 更改为IntPtr。这是有道理的,因为这篇文章专门讨论了匹配 C 和 C# 数据类型的主题。
不确定,但也许您应该调查一下magic numbers。
更新: 读了一遍,我认为它不是很可靠。
【讨论】:
FindMimeData 甚至没有检测到像audio/mp3 这样基本的东西,所以如果你检测到这 26 种类型之外的东西,幻数是唯一的选择。你能详细说明为什么你认为它不可靠吗?
您无法从字节流中知道它,但您可以在最初填充 byte[] 时存储 MIME 类型。
【讨论】:
file 命令所做的那样)。你可以查看它的来源。
如果你知道这是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 会引发异常。
简短的回答:你不能
更长的答案:通常,程序使用文件扩展名来了解它们正在处理的文件类型。如果您没有该扩展名,则只能进行猜测...例如,您可以查看前几个字节并检查您是否识别出众所周知的标头(例如 XML 声明标记,或位图或 JPEG 标头)。但这最终总是一个猜测:没有一些元数据或有关内容的信息,字节数组就毫无意义......
【讨论】:
如果您知道文件名的扩展名,那么 System.Web.MimeMapping 可能会解决问题:
MimeMapping.GetMimeMapping(fileDisplayNameWithExtension)
我在 MVC Action 中这样使用它:
return File(fileDataByteArray, MimeMapping.GetMimeMapping(fileDisplayNameWithExtension), fileDisplayNameWithExtension);
【讨论】:
让我想起了我们,呃,“某些人”过去在早期的免费图片托管网站上共享 50MB 的 rar 文件,只需将 .gif 扩展名添加到 .rar 文件名。
很明显,如果您是面向公众的并且您期望某种文件类型,并且您必须确保它是该文件类型,那么您就不能只信任扩展名。
另一方面,如果您的应用没有理由不信任上传的扩展名和/或 MIME 类型,那么只需在文件上传时获取这些内容,就像您从 @rossfabircant 和 @RandolphPotter 收到的答案一样。创建一个具有 byte[] 以及原始扩展名或 mimetype 的类型,然后传递它。
如果您需要验证文件实际上是某种预期类型,例如有效的 .jpeg 或 .png,您可以尝试将文件解释为这些类型并查看它是否成功打开。 (System.Drawing.Imaging.ImageFormat)
如果您尝试仅从二进制内容中对文件进行分类,并且它可能是整个世界中的任何格式,这确实是一个棘手的开放式问题,并且没有 100% 可靠的方法来做到这一点.您可以针对它调用TrID,如果您能找到(并负担得起)它们,执法调查人员可能会使用类似的取证工具。
如果您不必以艰难的方式去做,请不要这样做。
【讨论】:
你不想那样做。上传文件时调用 Path.GetExtension,并使用 byte[] 传递扩展名。
【讨论】:
如果您希望支持的预期文件类型数量有限,则可以使用幻数。
一个简单的检查方法是使用文本/十六进制编辑器打开示例文件,并研究前导字节,看看是否有一些东西可以用来区分/丢弃受支持集合中的文件。
另一方面,如果您希望识别任意文件类型,是的,正如大家已经说过的那样,很难。
【讨论】:
使用 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
【讨论】: