【问题标题】:Get file type in .NET在 .NET 中获取文件类型
【发布时间】:2010-11-29 01:44:16
【问题描述】:

如何使用 c# 获取文件类型。 例如,如果文件名 id “abc.png”和文件类型将“PNG Image”与窗口资源管理器中的第三列“Type”相同。

【问题讨论】:

    标签: c# .net file


    【解决方案1】:

    您需要 P/Invoke 到 SHGetFileInfo 以获取文件类型信息。这是一个完整的示例:

    using System;
    using System.Runtime.InteropServices;
    
    static class NativeMethods
    {
        [StructLayout(LayoutKind.Sequential)]
        public struct SHFILEINFO
        {
            public IntPtr hIcon;
            public int iIcon;
            public uint dwAttributes;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
            public string szDisplayName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
            public string szTypeName;
        };
    
        public static class FILE_ATTRIBUTE
        {
            public const uint FILE_ATTRIBUTE_NORMAL = 0x80;
        }
    
        public static class SHGFI
        {
            public const uint SHGFI_TYPENAME = 0x000000400;
            public const uint SHGFI_USEFILEATTRIBUTES = 0x000000010;
        }
    
        [DllImport("shell32.dll")]
        public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);
    }
    
    class Program
    {
        public static void Main(string[] args)
        {
            NativeMethods.SHFILEINFO info = new NativeMethods.SHFILEINFO();
    
            string fileName = @"C:\Some\Path\SomeFile.png";
            uint dwFileAttributes = NativeMethods.FILE_ATTRIBUTE.FILE_ATTRIBUTE_NORMAL;
            uint uFlags = (uint)(NativeMethods.SHGFI.SHGFI_TYPENAME | NativeMethods.SHGFI.SHGFI_USEFILEATTRIBUTES);
    
            NativeMethods.SHGetFileInfo(fileName, dwFileAttributes, ref info, (uint)Marshal.SizeOf(info), uFlags);
    
            Console.WriteLine(info.szTypeName);
        }
    }
    

    【讨论】:

    • 这个答案应该是公认的答案,因为它还展示了如何使用它,比当前接受的答案要好得多。 +1
    • 但是,它并没有真正起作用,当我将文件从 txt 更改为 png 格式时,它告诉我这是一个 PNG 格式的文件。当然,该文件已经过隐写过程,并使用该过程提取,但已加密。
    • 这是最好的答案。
    【解决方案2】:

    您需要使用 Windows API SHGetFileInfo function

    在输出结构中,szTypeName 包含您要查找的名称。

    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
    public struct SHFILEINFO
    {
         public IntPtr hIcon;
         public int iIcon;
         public uint dwAttributes;
    
         [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
         public string szDisplayName;
    
         [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
         public string szTypeName;
    };
    

    请注意,这只是存储在 Windows 注册表中的当前“友好名称”,它只是一个标签(但对于您的情况可能已经足够了)。

    szTypeName 和 szDisplayName 的区别在 MSDN 中有描述:

    szTypeName: 以 Null 结尾的字符串 描述文件的类型。

    szDisplayName: 以 Null 结尾的字符串 包含文件的名称为 它出现在 Windows shell 中,或者 文件的路径和名称 包含代表 文件。

    为了更准确地确定文件类型,您需要读取每个文件的第一个字节块并将其与已发布的文件规范进行比较。有关文件格式的信息,请参见 Wotsit 之类的网站。

    链接页面还包含完整的示例 C# 代码。

    【讨论】:

    • 您可能需要更正您的帖子 - szTypeName 有信息,而不是 szDisplayName。请参阅msdn.microsoft.com/en-us/library/aa453689.aspx => szDisplayName:以 Null 结尾的字符串,其中包含文件在 Windows shell 中显示的名称,或包含代表该文件的图标的文件的路径和名称。
    【解决方案3】:

    P/invoke 到SHGetFileInfo,并检查返回结构中的 szDisplayName。结果将取决于您如何定义文件类型(即它不是绝对参考)。但在大多数情况下应该没问题。 Click here for the c# signature of SHGetFileInfo and example code on pinvoke.net(真棒网站)

    对于绝对引用,您需要检查二进制标头中的几个字节并与这些字节的已知列表进行比较 - 我认为这是基于 unix 的系统默认执行此操作的方式。

    【讨论】:

      【解决方案4】:

      Win-API 函数 SHGetFileInfo() 是您的朋友。查看 here 获取一些代码 sn-ps。

      【讨论】:

        【解决方案5】:

        如果您不想使用 P/Invoke 而是想自己查看注册表:

        private Dictionary<string, string> GetRegistryFileTypes()
        {
          Dictionary<string, string> results = new Dictionary<string, string>();
        
          using (RegistryKey rootKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Explorer\KindMap"))
            if (rootKey != null)
              foreach (string currSubKey in rootKey.GetValueNames())
                results.Add(currSubKey, rootKey.GetValue(currSubKey).ToString());
        
          return results;
        }
        

        然后你可以使用扩展作为key来获取扩展的Registry数据:

        string fileType = GetRegistryFileTypes()[Path.GetExtension(filePath)];
        
        if (fileType != null && fileType.Length > 0)
          // do whatever here
        

        【讨论】:

          猜你喜欢
          • 2014-08-02
          • 2019-09-09
          • 2015-01-29
          • 2015-12-20
          • 2020-10-25
          • 2021-10-13
          • 2013-04-26
          • 2021-04-02
          • 2012-06-14
          相关资源
          最近更新 更多