我正在寻找一种简单的方法来获得mime类型,其中文件扩展名是不正确的或没有给出,类似于这个问题只有在. net。
当前回答
您也可以查看注册表。
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数据库——无论它们是从扩展还是魔术数字映射的,都有点微不足道——windows注册表就是这样一个地方。 对于独立于平台的解决方案,必须将此DB与代码一起发布(或作为独立的库)。
其他回答
编辑:只需使用Mime侦探
我使用字节数组序列来确定给定文件的正确MIME类型。与只查看文件名的文件扩展名相比,这样做的好处是,如果用户要重命名一个文件以绕过某些文件类型的上传限制,则文件扩展名将无法捕捉到这一点。另一方面,通过字节数组获取文件签名将阻止这种有害行为的发生。
下面是c#中的一个例子:
public class MimeType
{
private static readonly byte[] BMP = { 66, 77 };
private static readonly byte[] DOC = { 208, 207, 17, 224, 161, 177, 26, 225 };
private static readonly byte[] EXE_DLL = { 77, 90 };
private static readonly byte[] GIF = { 71, 73, 70, 56 };
private static readonly byte[] ICO = { 0, 0, 1, 0 };
private static readonly byte[] JPG = { 255, 216, 255 };
private static readonly byte[] MP3 = { 255, 251, 48 };
private static readonly byte[] OGG = { 79, 103, 103, 83, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0 };
private static readonly byte[] PDF = { 37, 80, 68, 70, 45, 49, 46 };
private static readonly byte[] PNG = { 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82 };
private static readonly byte[] RAR = { 82, 97, 114, 33, 26, 7, 0 };
private static readonly byte[] SWF = { 70, 87, 83 };
private static readonly byte[] TIFF = { 73, 73, 42, 0 };
private static readonly byte[] TORRENT = { 100, 56, 58, 97, 110, 110, 111, 117, 110, 99, 101 };
private static readonly byte[] TTF = { 0, 1, 0, 0, 0 };
private static readonly byte[] WAV_AVI = { 82, 73, 70, 70 };
private static readonly byte[] WMV_WMA = { 48, 38, 178, 117, 142, 102, 207, 17, 166, 217, 0, 170, 0, 98, 206, 108 };
private static readonly byte[] ZIP_DOCX = { 80, 75, 3, 4 };
public static string GetMimeType(byte[] file, string fileName)
{
string mime = "application/octet-stream"; //DEFAULT UNKNOWN MIME TYPE
//Ensure that the filename isn't empty or null
if (string.IsNullOrWhiteSpace(fileName))
{
return mime;
}
//Get the file extension
string extension = Path.GetExtension(fileName) == null
? string.Empty
: Path.GetExtension(fileName).ToUpper();
//Get the MIME Type
if (file.Take(2).SequenceEqual(BMP))
{
mime = "image/bmp";
}
else if (file.Take(8).SequenceEqual(DOC))
{
mime = "application/msword";
}
else if (file.Take(2).SequenceEqual(EXE_DLL))
{
mime = "application/x-msdownload"; //both use same mime type
}
else if (file.Take(4).SequenceEqual(GIF))
{
mime = "image/gif";
}
else if (file.Take(4).SequenceEqual(ICO))
{
mime = "image/x-icon";
}
else if (file.Take(3).SequenceEqual(JPG))
{
mime = "image/jpeg";
}
else if (file.Take(3).SequenceEqual(MP3))
{
mime = "audio/mpeg";
}
else if (file.Take(14).SequenceEqual(OGG))
{
if (extension == ".OGX")
{
mime = "application/ogg";
}
else if (extension == ".OGA")
{
mime = "audio/ogg";
}
else
{
mime = "video/ogg";
}
}
else if (file.Take(7).SequenceEqual(PDF))
{
mime = "application/pdf";
}
else if (file.Take(16).SequenceEqual(PNG))
{
mime = "image/png";
}
else if (file.Take(7).SequenceEqual(RAR))
{
mime = "application/x-rar-compressed";
}
else if (file.Take(3).SequenceEqual(SWF))
{
mime = "application/x-shockwave-flash";
}
else if (file.Take(4).SequenceEqual(TIFF))
{
mime = "image/tiff";
}
else if (file.Take(11).SequenceEqual(TORRENT))
{
mime = "application/x-bittorrent";
}
else if (file.Take(5).SequenceEqual(TTF))
{
mime = "application/x-font-ttf";
}
else if (file.Take(4).SequenceEqual(WAV_AVI))
{
mime = extension == ".AVI" ? "video/x-msvideo" : "audio/x-wav";
}
else if (file.Take(16).SequenceEqual(WMV_WMA))
{
mime = extension == ".WMA" ? "audio/x-ms-wma" : "video/x-ms-wmv";
}
else if (file.Take(4).SequenceEqual(ZIP_DOCX))
{
mime = extension == ".DOCX" ? "application/vnd.openxmlformats-officedocument.wordprocessingml.document" : "application/x-zip-compressed";
}
return mime;
}
}
注意,我对DOCX文件类型的处理是不同的,因为DOCX实际上只是一个ZIP文件。在这个场景中,只要验证了文件扩展名的顺序,我就会检查文件扩展名。对于某些人来说,这个示例还远远不够完整,但是您可以轻松地添加自己的示例。
如果您想添加更多MIME类型,您可以从这里获得许多不同文件类型的字节数组序列。另外,这里还有一个关于文件签名的很好的资源。
如果其他方法都失败了,我经常做的是逐步查看我正在寻找的特定类型的几个文件,并在文件的字节序列中寻找模式。最后,这仍然是基本的验证,不能用于确定文件类型的100%证明。
如果你正在使用。net Framework 4.5或更高版本,现在有一个MimeMapping.GetMimeMapping(filename)方法,它将返回一个字符串,其中包含传递文件名的正确Mime映射。注意,这里使用的是文件扩展名,而不是文件本身中的数据。
文档请见http://msdn.microsoft.com/en-us/library/system.web.mimemapping.getmimemapping
如果有人对此感兴趣,他们可以将优秀的perl模块File::Type移植到。net。在代码中是一组文件头魔术数字查找每个文件类型或正则表达式匹配。
这里有一个。net文件类型检测库http://filetypedetective.codeplex.com/,但它目前只检测少量的文件。
你好,我已经改编了Winista。MimeDetect项目到。net core/framework,回退到urlmon.dll,自由使用它:nuget包。
//init
var mimeTypes = new MimeTypes();
//usage by filepath
var mimeType1 = mimeTypes.GetMimeTypeFromFile(filePath);
我发现运行这段代码有几个问题:
UInt32 mimetype;
FindMimeFromData(0, null, buffer, 256, null, 0, out mimetype, 0);
如果你尝试用x64/Win10运行它,你会得到
AccessViolationException "Attempted to read or write protected memory.
This is often an indication that other memory is corrupt"
多亏了这篇文章,PtrToStringUni在windows 10和@xanatos中无法工作
我修改了我的解决方案,在x64和。net Core 2.1下运行:
[DllImport("urlmon.dll", CharSet = CharSet.Unicode, ExactSpelling = true,
SetLastError = false)]
static extern int FindMimeFromData(IntPtr pBC,
[MarshalAs(UnmanagedType.LPWStr)] string pwzUrl,
[MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.I1,
SizeParamIndex=3)]
byte[] pBuffer,
int cbSize,
[MarshalAs(UnmanagedType.LPWStr)] string pwzMimeProposed,
int dwMimeFlags,
out IntPtr ppwzMimeOut,
int dwReserved);
string getMimeFromFile(byte[] fileSource)
{
byte[] buffer = new byte[256];
using (Stream stream = new MemoryStream(fileSource))
{
if (stream.Length >= 256)
stream.Read(buffer, 0, 256);
else
stream.Read(buffer, 0, (int)stream.Length);
}
try
{
IntPtr mimeTypePtr;
FindMimeFromData(IntPtr.Zero, null, buffer, buffer.Length,
null, 0, out mimeTypePtr, 0);
string mime = Marshal.PtrToStringUni(mimeTypePtr);
Marshal.FreeCoTaskMem(mimeTypePtr);
return mime;
}
catch (Exception ex)
{
return "unknown/unknown";
}
}
谢谢
推荐文章
- 实体框架核心:在上一个操作完成之前,在此上下文中开始的第二个操作
- 如何为构造函数定制Visual Studio的私有字段生成快捷方式?
- 如何使用JSON确保字符串是有效的JSON。网
- AppSettings从.config文件中获取值
- 通过HttpClient向REST API发布一个空体
- 如何检查IEnumerable是否为空或空?
- 自动化invokerrequired代码模式
- 在c#代码中设置WPF文本框的背景颜色
- 在c#中,什么是单子?
- c#和Java中的泛型有什么不同?和模板在c++ ?
- c#线程安全快速(est)计数器
- 如何将此foreach代码转换为Parallel.ForEach?
- 如何分裂()一个分隔字符串到一个列表<字符串>
- 如何转换列表<字符串>列表<int>?
- c#对象列表,我如何得到一个属性的和