我正在寻找一种简单的方法来获得mime类型,其中文件扩展名是不正确的或没有给出,类似于这个问题只有在. net。
当前回答
@Steve Morgan和@Richard Gourlay,这是一个很好的解决方案,谢谢你们。一个小缺点是,当文件中的字节数为255或以下时,mime类型有时会产生“application/octet-stream”,这对于期望产生“text/plain”的文件来说有点不准确。对于这种情况,我更新了你原来的方法如下:
如果文件中的字节数小于或等于255,并且推导出的mime类型是"application/octet-stream",那么创建一个新的字节数组,该数组由重复n次的原始文件字节组成,直到字节总数为>= 256。然后重新检查新字节数组上的mime-type。
修改方法:
Imports System.Runtime.InteropServices
<DllImport("urlmon.dll", CharSet:=CharSet.Auto)> _
Private Shared Function FindMimeFromData(pBC As System.UInt32, <MarshalAs(UnmanagedType.LPStr)> pwzUrl As System.String, <MarshalAs(UnmanagedType.LPArray)> pBuffer As Byte(), cbSize As System.UInt32, <MarshalAs(UnmanagedType.LPStr)> pwzMimeProposed As System.String, dwMimeFlags As System.UInt32, _
ByRef ppwzMimeOut As System.UInt32, dwReserverd As System.UInt32) As System.UInt32
End Function
Private Function GetMimeType(ByVal f As FileInfo) As String
'See http://stackoverflow.com/questions/58510/using-net-how-can-you-find-the-mime-type-of-a-file-based-on-the-file-signature
Dim returnValue As String = ""
Dim fileStream As FileStream = Nothing
Dim fileStreamLength As Long = 0
Dim fileStreamIsLessThanBByteSize As Boolean = False
Const byteSize As Integer = 255
Const bbyteSize As Integer = byteSize + 1
Const ambiguousMimeType As String = "application/octet-stream"
Const unknownMimeType As String = "unknown/unknown"
Dim buffer As Byte() = New Byte(byteSize) {}
Dim fnGetMimeTypeValue As New Func(Of Byte(), Integer, String)(
Function(_buffer As Byte(), _bbyteSize As Integer) As String
Dim _returnValue As String = ""
Dim mimeType As UInt32 = 0
FindMimeFromData(0, Nothing, _buffer, _bbyteSize, Nothing, 0, mimeType, 0)
Dim mimeTypePtr As IntPtr = New IntPtr(mimeType)
_returnValue = Marshal.PtrToStringUni(mimeTypePtr)
Marshal.FreeCoTaskMem(mimeTypePtr)
Return _returnValue
End Function)
If (f.Exists()) Then
Try
fileStream = New FileStream(f.FullName(), FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
fileStreamLength = fileStream.Length()
If (fileStreamLength >= bbyteSize) Then
fileStream.Read(buffer, 0, bbyteSize)
Else
fileStreamIsLessThanBByteSize = True
fileStream.Read(buffer, 0, CInt(fileStreamLength))
End If
returnValue = fnGetMimeTypeValue(buffer, bbyteSize)
If (returnValue.Equals(ambiguousMimeType, StringComparison.OrdinalIgnoreCase) AndAlso fileStreamIsLessThanBByteSize AndAlso fileStreamLength > 0) Then
'Duplicate the stream content until the stream length is >= bbyteSize to get a more deterministic mime type analysis.
Dim currentBuffer As Byte() = buffer.Take(fileStreamLength).ToArray()
Dim repeatCount As Integer = Math.Floor((bbyteSize / fileStreamLength) + 1)
Dim bBufferList As List(Of Byte) = New List(Of Byte)
While (repeatCount > 0)
bBufferList.AddRange(currentBuffer)
repeatCount -= 1
End While
Dim bbuffer As Byte() = bBufferList.Take(bbyteSize).ToArray()
returnValue = fnGetMimeTypeValue(bbuffer, bbyteSize)
End If
Catch ex As Exception
returnValue = unknownMimeType
Finally
If (fileStream IsNot Nothing) Then fileStream.Close()
End Try
End If
Return returnValue
End Function
其他回答
iis7或以上
使用此代码,但您需要是服务器上的管理员
public bool CheckMimeMapExtension(string fileExtension)
{
try
{
using (
ServerManager serverManager = new ServerManager())
{
// connects to default app.config
var config = serverManager.GetApplicationHostConfiguration();
var staticContent = config.GetSection("system.webServer/staticContent");
var mimeMap = staticContent.GetCollection();
foreach (var mimeType in mimeMap)
{
if (((String)mimeType["fileExtension"]).Equals(fileExtension, StringComparison.OrdinalIgnoreCase))
return true;
}
}
return false;
}
catch (Exception ex)
{
Console.WriteLine("An exception has occurred: \n{0}", ex.Message);
Console.Read();
}
return false;
}
您也可以查看注册表。
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与代码一起发布(或作为独立的库)。
我发现运行这段代码有几个问题:
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";
}
}
谢谢
如果你正在使用。net Framework 4.5或更高版本,现在有一个MimeMapping.GetMimeMapping(filename)方法,它将返回一个字符串,其中包含传递文件名的正确Mime映射。注意,这里使用的是文件扩展名,而不是文件本身中的数据。
文档请见http://msdn.microsoft.com/en-us/library/system.web.mimemapping.getmimemapping
你好,我已经改编了Winista。MimeDetect项目到。net core/framework,回退到urlmon.dll,自由使用它:nuget包。
//init
var mimeTypes = new MimeTypes();
//usage by filepath
var mimeType1 = mimeTypes.GetMimeTypeFromFile(filePath);
推荐文章
- 实体框架核心:在上一个操作完成之前,在此上下文中开始的第二个操作
- 如何为构造函数定制Visual Studio的私有字段生成快捷方式?
- 如何使用JSON确保字符串是有效的JSON。网
- AppSettings从.config文件中获取值
- 通过HttpClient向REST API发布一个空体
- 如何检查IEnumerable是否为空或空?
- 自动化invokerrequired代码模式
- 在c#代码中设置WPF文本框的背景颜色
- 在c#中,什么是单子?
- c#和Java中的泛型有什么不同?和模板在c++ ?
- c#线程安全快速(est)计数器
- 如何将此foreach代码转换为Parallel.ForEach?
- 如何分裂()一个分隔字符串到一个列表<字符串>
- 如何转换列表<字符串>列表<int>?
- c#对象列表,我如何得到一个属性的和