【问题标题】:How do I determine a file's content type in .NET?如何在 .NET 中确定文件的内容类型?
【发布时间】:2009-03-27 19:38:30
【问题描述】:

我的 WPF 应用程序使用 Microsoft.Win32.OpenFileDialog() 从用户那里获取文件...

Private Sub ButtonUpload_Click(...)
    Dim FileOpenStream As Stream = Nothing
    Dim FileBox As New Microsoft.Win32.OpenFileDialog()
    FileBox.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
    FileBox.Filter = "Pictures (*.jpg;*.jpeg;*.gif;*.png)|*.jpg;*.jpeg;*.gif;*.png|" & _
                     "Documents (*.pdf;*.doc;*.docx;)|*.pdf;*.doc;*.docx;|" & _
                     "All Files (*.*)|*.*"
    FileBox.FilterIndex = 1
    FileBox.Multiselect = False
    Dim FileSelected As Nullable(Of Boolean) = FileBox.ShowDialog(Me)
    If FileSelected IsNot Nothing AndAlso FileSelected.Value = True Then
        Try
            FileOpenStream = FileBox.OpenFile()
            If (FileOpenStream IsNot Nothing) Then
                Dim ByteArray As Byte()
                Using br As New BinaryReader(FileOpenStream)
                    ByteArray = br.ReadBytes(FileOpenStream.Length)
                End Using
                Dim z As New ZackFile
                z.Id = Guid.NewGuid
                z.FileData = ByteArray
                z.FileSize = CInt(ByteArray.Length)
                z.FileName = FileBox.FileName.Split("\").Last
                z.DateAdded = Now
                db.AddToZackFile(z)
                db.SaveChanges()
            End If
        Catch Ex As Exception
            MessageBox.Show("Cannot read file from disk. " & Ex.Message, "Fail", MessageBoxButton.OK, MessageBoxImage.Error)
        Finally
            If (FileOpenStream IsNot Nothing) Then
                FileOpenStream.Close()
            End If
        End Try
    End If
End Sub

我的 ASP.NET MVC 应用程序通过 FileStreamResult() 在网站上提供下载...

Public Class ZackFileController
    Inherits System.Web.Mvc.Controller

    Function Display(ByVal id As Guid) As FileStreamResult
        Dim db As New EfrDotOrgEntities
        Dim Model As ZackFile = (From z As ZackFile In db.ZackFile _
                                Where z.Id = id _
                                Select z).First
        Dim ByteArray As Byte() = Model.ImageData
        Dim FileStream As System.IO.MemoryStream = New System.IO.MemoryStream(ByteArray)
        Dim ContentType As String = ?????
        Dim f As New FileStreamResult(FileStream, ContentType)
        f.FileDownloadName = Model.FileName
        Return f
    End Function

End Class

但是 FileStreamResult() 需要一个内容类型字符串。我如何知道我的文件的正确内容类型?

【问题讨论】:

  • 页面内部如何使用Display功能?
  • 没有页面。那是一个 ASP.NET MVC 控制器类。显示是其视图之一。但是,因为这个 View 返回的是 FileStreamResult 而不是 ViewResult,所以它没有 ASPX 页面。

标签: .net file file-io content-type mime-types


【解决方案1】:

【讨论】:

  • 太棒了,比我自己提取信息并创建 MimeMapping 表要好得多。
  • 但是....NET 中的 MimeMapping 类只是映射到文件名字符串中给定的扩展名。它不检查魔术字节。
【解决方案2】:

我已将数据库表中的 FileExtension 列替换为 ContentType 列。

我在上传文件时填充它。

Private Sub ButtonUpload_Click(...)
    ...
    Dim FileExtension As String = "." + FileBox.FileName.Split(".").Last.ToLower
    z.ContentType = ContentType(FileExtension)
    ...
End Sub

我用这个函数确定内容类型:

Function ContentType(ByVal FileExtension As String) As String
    Dim d As New Dictionary(Of String, String)
    'Images'
    d.Add(".bmp", "image/bmp")
    d.Add(".gif", "image/gif")
    d.Add(".jpeg", "image/jpeg")
    d.Add(".jpg", "image/jpeg")
    d.Add(".png", "image/png")
    d.Add(".tif", "image/tiff")
    d.Add(".tiff", "image/tiff")
    'Documents'
    d.Add(".doc", "application/msword")
    d.Add(".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document")
    d.Add(".pdf", "application/pdf")
    'Slideshows'
    d.Add(".ppt", "application/vnd.ms-powerpoint")
    d.Add(".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation")
    'Data'
    d.Add(".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
    d.Add(".xls", "application/vnd.ms-excel")
    d.Add(".csv", "text/csv")
    d.Add(".xml", "text/xml")
    d.Add(".txt", "text/plain")
    'Compressed Folders'
    d.Add(".zip", "application/zip")
    'Audio'
    d.Add(".ogg", "application/ogg")
    d.Add(".mp3", "audio/mpeg")
    d.Add(".wma", "audio/x-ms-wma")
    d.Add(".wav", "audio/x-wav")
    'Video'
    d.Add(".wmv", "audio/x-ms-wmv")
    d.Add(".swf", "application/x-shockwave-flash")
    d.Add(".avi", "video/avi")
    d.Add(".mp4", "video/mp4")
    d.Add(".mpeg", "video/mpeg")
    d.Add(".mpg", "video/mpeg")
    d.Add(".qt", "video/quicktime")
    Return d(FileExtension)
End Function

这行得通,但看起来不优雅。

【讨论】:

  • 您可能应该使用 switch 语句而不是每次调用 ContentType 时都构建一个新字典。此外,还有一个Path.GetExtension 方法,因此您不必手动拆分文件名。
  • VB.Net 10 更好一点... Dim d As New Dictionary(Of String, String) From { {".bmp", "image/bmp"}, {".gif" , "image/gif"}, {".jpeg", "image/jpeg"}} '等
  • @StriplingWarrior,或者保留一个静态字典。如果该方法经常使用并且支持那么多文件扩展名,我认为它会加快一点
  • @IvayloSlavov:字典可能是个好主意,特别是如果您希望支持的扩展列表是动态的,或者从配置文件或其他东西中加载它。但它不会更快。编译器足够聪明,可以使用字典或其他结构来实现 switch 语句,具体取决于它认为它将如何获得更好的性能。
  • @StriplingWarrior,是的,你说得对,编译器能够用最终代码做一些白魔法。尽管如此,我还是会选择字典,因为它比 switch 语句提供了更多的灵活性,而且我可以用外部数据填充它,可能来自配置或数据库。
【解决方案3】:

我在 web.config 中使用了自定义配置部分(我将编写自定义配置部分的任务留给您):

<configSections>
    <section name="mimeTypeMappings" type="MySoftwareLol.MimeTypeMappingSection, MySoftwareLol"/>
</configSections>

<mimeTypeMappings>
    <MimeTypes>
      <MimeType Type="application/mac-binhex40" Extensions=".hqx"/>
      <MimeType Type="application/msword" Extensions=".doc"/>
      <MimeType Type="application/pdf" Extensions=".pdf"/>
      <MimeType Type="application/postscript" Extensions=".ai;.eps;.ps"/>
      <MimeType Type="application/rtf" Extensions=".rtf"/>
      <MimeType Type="application/vnd.ms-excel" Extensions=".xla;.xlc;.xlm;.xls;.xlt;.xlw"/>
      <MimeType Type="application/vnd.ms-outlook" Extensions=".msg"/>
      <MimeType Type="application/vnd.ms-powerpoint" Extensions=".pot;.pps;.ppt"/>
      <MimeType Type="application/vnd.ms-works" Extensions=".wcm;.wdb;.wks;.wps"/>
      <MimeType Type="application/x-compress" Extensions=".z"/>
      <MimeType Type="application/x-compressed" Extensions=".tgz"/>
      <MimeType Type="application/x-gzip" Extensions=".gz"/>
      <MimeType Type="application/x-msaccess" Extensions=".mdb"/>
      <MimeType Type="application/x-msmetafile" Extensions=".wmf"/>
      <MimeType Type="application/x-mspublisher" Extensions=".pub"/>
      <MimeType Type="application/x-msschedule" Extensions=".scd"/>
      <MimeType Type="application/x-msterminal" Extensions=".trm"/>
      <MimeType Type="application/x-mswrite" Extensions=".wri"/>
      <MimeType Type="application/x-tar" Extensions=".tar"/>
      <MimeType Type="application/zip" Extensions=".zip"/>
      <MimeType Type="audio/basic" Extensions=".au;.snd"/>
      <MimeType Type="audio/mid" Extensions=".mid;.rmi"/>
      <MimeType Type="audio/mpeg" Extensions=".mp3"/>
      <MimeType Type="audio/x-aiff" Extensions=".aif;.aifc;.aiff"/>
      <MimeType Type="audio/x-pn-realaudio" Extensions=".ra;.ram"/>
      <MimeType Type="audio/x-wav" Extensions=".wav"/>
      <MimeType Type="image/bmp" Extensions=".bmp"/>
      <MimeType Type="image/gif" Extensions=".gif"/>
      <MimeType Type="image/jpeg" Extensions=".jpe;.jpeg;.jpg"/>
      <MimeType Type="image/pipeg" Extensions=".jfif"/>
      <MimeType Type="image/tiff" Extensions=".tif;.tiff"/>
      <!--By default, sends HTML documents as plain text; sending it as text/html may pose security risks-->
      <!--If you wish to accept the risks, uncomment the following two lines and comment out the third.-->
      <!--<MimeType Type="text/html" Extensions=".mht;.html;.htm"/>-->
      <!--<MimeType Type="text/plain" Extensions=".txt"/>-->
      <MimeType Type="text/plain" Extensions=".txt;.html;.htm"/>
      <MimeType Type="text/richtext" Extensions=".rtx"/>
      <MimeType Type="text/tab-separated-values" Extensions=".tsv"/>
      <MimeType Type="video/mpeg" Extensions=".mp2;.mpa;.mpe;.mpeg;.mpg;.mpv2"/>
      <MimeType Type="video/quicktime" Extensions=".mov;.qt"/>
      <MimeType Type="video/x-la-asf" Extensions=".lsf;.lsx;.asf;.asr;.asx;"/>
      <MimeType Type="video/x-msvideo" Extensions=".avi"/>
    </MimeTypes>
  </mimeTypeMappings>

我使用 Path.GetExtension() 并将其映射到 Extensions 中列出的类型之一。

【讨论】:

    【解决方案4】:

    我根据 Zacks 响应创建了一个 C# 助手类。

    /// <summary>
    /// Helps with Mime Types
    /// </summary>
    public static class MimeTypesHelper
    {
        /// <summary>
        /// Returns the content type based on the given file extension
        /// </summary>
        public static string GetContentType(string fileExtension)
        {
            var mimeTypes = new Dictionary<String, String>
                {
                    {".bmp", "image/bmp"},
                    {".gif", "image/gif"},
                    {".jpeg", "image/jpeg"},
                    {".jpg", "image/jpeg"},
                    {".png", "image/png"},
                    {".tif", "image/tiff"},
                    {".tiff", "image/tiff"},
                    {".doc", "application/msword"},
                    {".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
                    {".pdf", "application/pdf"},
                    {".ppt", "application/vnd.ms-powerpoint"},
                    {".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
                    {".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
                    {".xls", "application/vnd.ms-excel"},
                    {".csv", "text/csv"},
                    {".xml", "text/xml"},
                    {".txt", "text/plain"},
                    {".zip", "application/zip"},
                    {".ogg", "application/ogg"},
                    {".mp3", "audio/mpeg"},
                    {".wma", "audio/x-ms-wma"},
                    {".wav", "audio/x-wav"},
                    {".wmv", "audio/x-ms-wmv"},
                    {".swf", "application/x-shockwave-flash"},
                    {".avi", "video/avi"},
                    {".mp4", "video/mp4"},
                    {".mpeg", "video/mpeg"},
                    {".mpg", "video/mpeg"},
                    {".qt", "video/quicktime"}
                };
    
            // if the file type is not recognized, return "application/octet-stream" so the browser will simply download it
            return mimeTypes.ContainsKey(fileExtension) ? mimeTypes[fileExtension] : "application/octet-stream";
        }
    }
    

    当然,您可能希望保持mimeTypes 处于活动状态以供将来查询。这只是一个起点。

    【讨论】:

      【解决方案5】:

      当您设置内容类型时,您似乎仍然拥有文件名。您可以为文件扩展名选择正确的 mime 类型,或者默认为“application/base64”之类的类型。

      假设下载它的人将使用网络浏览器,请尝试使用常用浏览器:MIME Types Known By IE

      【讨论】:

      • 这对于任何要通过渗透测试的东西来说都不够可靠。我可以使用此示例上传重命名为 .docx 的 .exe。
      【解决方案6】:

      可以通过使用注册表项轻松完成。

      Dim regKey As Microsoft.Win32.RegistryKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey("extension")
      If Not regKey Is Nothing Then
      Dim ct As Object = regKey.GetValue("Content Type")
        If Not ct Is Nothing Then
           Return ct.ToString()
        End If
      End If
      

      这将产生与上面提到的大列表相同的结果!!!!

      【讨论】:

      • 这应该是答案。
      【解决方案7】:

      您可以使用This 列表,其中包含 684 个文件扩展名。

      在这个列表中,每一个pair都用“~”分隔,每对的扩展名和内容类型用“#”分隔。

      我不知道您使用的是什么语言,但这是在 vb.net 中

      使用方法:

      1. 将字符串资源添加到包含该列表的项目中。 它看起来像这样 -
      2. 将此类添加到您的项目中(将字符串解析为字典)

        Public Class MIMETypeList
            Public data As Dictionary(Of String, String)
            Public Sub New()
               data = New Dictionary(Of String, String)()
               Dim Temp() As String
               For Each TypeConvertion As String In My.Resources.MimeType.Split("~")
                   Temp = TypeConvertion.Split("#")
                   If Not data.ContainsKey(Temp(0)) Then
                       data.Add(Temp(0), Temp(1))
                   End If
               Next
            End Sub
        End Class
        
      3. 现在你可以像这样使用它了:

        Dim FileExtension1 As String = ".mp4"
        Dim FileExtension2 As String = ".html"
        Dim FileExtension3 As String = ".Random"
        Dim Converter As New MIMETypeList
        If Converter.data.ContainsKey(FileExtension1) Then
            Debug.WriteLine(FileExtension1 & " -> " & Converter.data.Item(FileExtension1))
        Else
            Debug.WriteLine(FileExtension1 & " -> File Content Not Found")
        End If
        If Converter.data.ContainsKey(FileExtension2) Then
            Debug.WriteLine(FileExtension2 & " -> " & Converter.data.Item(FileExtension2))
        Else
            Debug.WriteLine(FileExtension2 & " -> File Content Not Found")
        End If
        If Converter.data.ContainsKey(FileExtension3) Then
            Debug.WriteLine(FileExtension3 & " -> " & Converter.data.Item(FileExtension3))
        Else
            Debug.WriteLine(FileExtension3 & " -> File Content Not Found")
        End If
        

        输出:

        .mp4 -> 视频/mp4

        .html -> 文本/html

        .Random -> 文件内容未找到

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-02-09
        • 2018-05-27
        • 2011-11-03
        • 1970-01-01
        • 1970-01-01
        • 2015-07-31
        • 2011-03-13
        相关资源
        最近更新 更多