我正在寻找一种简单的方法来获得mime类型,其中文件扩展名是不正确的或没有给出,类似于这个问题只有在. net。
当前回答
我发现运行这段代码有几个问题:
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";
}
}
谢谢
其他回答
在Urlmon.dll中,有一个名为FindMimeFromData的函数。
来自文档
MIME类型检测或“数据嗅探”是指从二进制数据中确定适当的MIME类型的过程。最终结果取决于服务器提供的MIME类型头、文件扩展名和/或数据本身的组合。通常,只有前256字节的数据是重要的。
因此,从文件中读取第一个(最多)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数据库——无论它们是从扩展还是魔术数字映射的,都有点微不足道——windows注册表就是这样一个地方。 对于独立于平台的解决方案,必须将此DB与代码一起发布(或作为独立的库)。
如果你正在使用。net Framework 4.5或更高版本,现在有一个MimeMapping.GetMimeMapping(filename)方法,它将返回一个字符串,其中包含传递文件名的正确Mime映射。注意,这里使用的是文件扩展名,而不是文件本身中的数据。
文档请见http://msdn.microsoft.com/en-us/library/system.web.mimemapping.getmimemapping
我写了一个mime类型的验证器。请与您分享。
private readonly Dictionary<string, byte[]> _mimeTypes = new Dictionary<string, byte[]>
{
{"image/jpeg", new byte[] {255, 216, 255}},
{"image/jpg", new byte[] {255, 216, 255}},
{"image/pjpeg", new byte[] {255, 216, 255}},
{"image/apng", new byte[] {137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82}},
{"image/png", new byte[] {137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82}},
{"image/bmp", new byte[] {66, 77}},
{"image/gif", new byte[] {71, 73, 70, 56}},
};
private bool ValidateMimeType(byte[] file, string contentType)
{
var imageType = _mimeTypes.SingleOrDefault(x => x.Key.Equals(contentType));
return file.Take(imageType.Value.Length).SequenceEqual(imageType.Value);
}
推荐文章
- c#线程安全快速(est)计数器
- 如何将此foreach代码转换为Parallel.ForEach?
- 如何分裂()一个分隔字符串到一个列表<字符串>
- 如何转换列表<字符串>列表<int>?
- c#对象列表,我如何得到一个属性的和
- 我如何使用IValidatableObject?
- 如何指定最小值,但没有使用范围数据注释属性的最大小数?
- c# vs Java Enum(适合c#新手)
- c#消毒文件名
- 在EF中更新父实体时如何添加/更新子实体
- ASP。NET身份的默认密码散列器-它是如何工作的,它是安全的?
- 如何写一个JSON文件在c# ?
- 静态隐式运算符
- 不区分大小写列表搜索
- 'throw'和'throw new Exception()'的区别