如何在 .NET 中获取文件扩展名的描述

Posted

技术标签:

【中文标题】如何在 .NET 中获取文件扩展名的描述【英文标题】:How can I get the description of a file extension in .NET 【发布时间】:2011-04-16 08:29:11 【问题描述】:

嗨,

Windows 提供文件扩展名的描述,例如 .cpl 文件的“控制面板项”和 .daa 文件的“PowerISO 文件”。有什么方法可以在 .NET 中获取这些数据?我使用 C#,但可以阅读所有其他 .NET 语言。还有一种方法可以获得扩展的默认图标吗?任何帮助将不胜感激。

提前致谢

【问题讨论】:

非常类似于***.com/questions/1910097/content-type-by-extension @David Stratton,这不是同一个问题。您提到的问题是关于获取内容类型(MIME 类型)。这是关于获取文件类型的描述。 Get file type in .NET的可能重复 【参考方案1】:

您可以使用SHGetFileInfo API 来获取该信息。这是一个包装器方法:

    public static string GetFileTypeDescription(string fileNameOrExtension)
    
        SHFILEINFO shfi;
        if (IntPtr.Zero != SHGetFileInfo(
                            fileNameOrExtension,
                            FILE_ATTRIBUTE_NORMAL,
                            out shfi,
                            (uint)Marshal.SizeOf(typeof(SHFILEINFO)),
                            SHGFI_USEFILEATTRIBUTES | SHGFI_TYPENAME))
        
            return shfi.szTypeName;
        
        return null;
    

    [DllImport("shell32")]
    private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, out SHFILEINFO psfi, uint cbFileInfo, uint flags);

    [StructLayout(LayoutKind.Sequential)]
    private 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;
    

    private const uint FILE_ATTRIBUTE_READONLY = 0x00000001;
    private const uint FILE_ATTRIBUTE_HIDDEN = 0x00000002;
    private const uint FILE_ATTRIBUTE_SYSTEM = 0x00000004;
    private const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
    private const uint FILE_ATTRIBUTE_ARCHIVE = 0x00000020;
    private const uint FILE_ATTRIBUTE_DEVICE = 0x00000040;
    private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080;
    private const uint FILE_ATTRIBUTE_TEMPORARY = 0x00000100;
    private const uint FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200;
    private const uint FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400;
    private const uint FILE_ATTRIBUTE_COMPRESSED = 0x00000800;
    private const uint FILE_ATTRIBUTE_OFFLINE = 0x00001000;
    private const uint FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000;
    private const uint FILE_ATTRIBUTE_ENCRYPTED = 0x00004000;
    private const uint FILE_ATTRIBUTE_VIRTUAL = 0x00010000;

    private const uint SHGFI_ICON = 0x000000100;     // get icon
    private const uint SHGFI_DISPLAYNAME = 0x000000200;     // get display name
    private const uint SHGFI_TYPENAME = 0x000000400;     // get type name
    private const uint SHGFI_ATTRIBUTES = 0x000000800;     // get attributes
    private const uint SHGFI_ICONLOCATION = 0x000001000;     // get icon location
    private const uint SHGFI_EXETYPE = 0x000002000;     // return exe type
    private const uint SHGFI_SYSICONINDEX = 0x000004000;     // get system icon index
    private const uint SHGFI_LINKOVERLAY = 0x000008000;     // put a link overlay on icon
    private const uint SHGFI_SELECTED = 0x000010000;     // show icon in selected state
    private const uint SHGFI_ATTR_SPECIFIED = 0x000020000;     // get only specified attributes
    private const uint SHGFI_LARGEICON = 0x000000000;     // get large icon
    private const uint SHGFI_SMALLICON = 0x000000001;     // get small icon
    private const uint SHGFI_OPENICON = 0x000000002;     // get open icon
    private const uint SHGFI_SHELLICONSIZE = 0x000000004;     // get shell size icon
    private const uint SHGFI_PIDL = 0x000000008;     // pszPath is a pidl
    private const uint SHGFI_USEFILEATTRIBUTES = 0x000000010;     // use passed dwFileAttribute

(大多数常量实际上并没有在该代码中使用,但我还是把它们放在了以防你想让代码适应你的特定需求)

【讨论】:

这与在 c# 中使用 FileInfo 类有何不同或更好? (只是好奇) @Tony Abrams,FileInfo 类没有给你类型描述。否则,我认为它主要是 SHFILEINFO 的包装器...... using System.Runtime.InteropServices; 需要【参考方案2】:

为了使用SHGetFileInfo,该文件必须存在于磁盘上。如果您只有文件的名称,甚至只有扩展名,则需要直接从注册表中获取信息:

public static string GetFileTypeDisplayName(string extension) =>
    Registry.ClassesRoot.OpenSubKey(extension)?.GetValue(null) is string keyName ?
        Registry.ClassesRoot.OpenSubKey(keyName)?.GetValue(null) as string :
        null;

如果注册表中没有适合给定文件扩展名的条目,此方法将简单地返回 null

【讨论】:

【参考方案3】:

您可以像这样搜索注册表:

HKEY_CLASSES_ROOT 中搜索扩展名的默认值。例如HKEY_CLASSES_ROOT\.txt的默认值为txtfile。 然后搜索上一个结果的默认值:例如HKEY_CLASSES_ROOT\txtfile的默认值是Text Document

经过两次搜索,答案是文本文档

您可以通过RegEdit 测试任何其他扩展。

访问此链接:http://www.codeproject.com/KB/cs/GetFileTypeAndIcon.aspx?display=Print

这是这两个搜索的实现:

public static class Helper

    public static string GetFileDescription(string fileName)
    
        if (fileName == null)
        
            throw new ArgumentNullException("fileName");
        

        RegistryKey registryKey1 = null;
        RegistryKey registryKey2 = null;
        try
        
            FileInfo fileInfo = new FileInfo(fileName);

            if (string.IsNullOrEmpty(fileInfo.Extension))
            
                return string.Empty;
            

            string extension = fileInfo.Extension.ToLowerInvariant();

            registryKey1 = Registry.ClassesRoot.OpenSubKey(extension);
            if (registryKey1 == null)
            
                return string.Empty;
            

            object extensionDefaultObject = registryKey1.GetValue(null);
            if (!(extensionDefaultObject is string))
            
                return string.Empty;
            

            string extensionDefaultValue = (string)extensionDefaultObject;

            registryKey2 = Registry.ClassesRoot.OpenSubKey(extensionDefaultValue);
            if (registryKey2 == null)
            
                return string.Empty;
            

            object fileDescriptionObject = registryKey2.GetValue(null);
            if (!(fileDescriptionObject is string))
            
                return string.Empty;
            

            string fileDescription = (string)fileDescriptionObject;
            return fileDescription;
        
        catch (Exception)
        
            return null;
        
        finally
        
            if (registryKey2 != null)
            
                registryKey2.Close();
            

            if (registryKey1 != null)
            
                registryKey1.Close();
            
        
    

【讨论】:

【参考方案4】:

扩展在 HKEY_CLASSES_ROOT 键中关联。所以你需要打开注册表,找到你感兴趣的值。你应该也可以在那里找到默认的图标。

Here 是一个示例项目(我没有尝试过)。

【讨论】:

你不会在那里找到像“控制面板项目”这样好的字符串 这里要注意的是扩展关联会因机器而异。 谢谢大家。 SHGetFileInfo 似乎没有注册表操作那么粗糙。 Andrey 还写了一些扩展名,就像 PowerISO 文件一样,但 .cpl 文件只是称为 cplfiles,而不是 Windows 内默认程序控制面板中显示的“控制面板项目”。谢谢Thomas 非常有帮助,对于将来需要更多参考的其他人support.microsoft.com/kb/319350 也展示了如何在 C# 中使用 SHGetFileInfo。【参考方案5】:

假设您的扩展名是 .xyz 要显示大多数用户友好的文本,例如“控制面板项”,您应该做两件事:

    转到 HKEY_CLASSES_ROOT 并搜索节点 xyzfile。检查“cplfile” 如果不存在,您可以在同一个地方获得关联,但节点是 .xyz 。它会告诉您打开它的应用程序,以便您获取名称。

【讨论】:

以上是关于如何在 .NET 中获取文件扩展名的描述的主要内容,如果未能解决你的问题,请参考以下文章

使用 .NET,如何根据文件签名而不是扩展名找到文件的 mime 类型

使用 .NET,如何根据文件签名而不是扩展名找到文件的 mime 类型

使用 .NET,如何根据文件签名而不是扩展名找到文件的 mime 类型

使用 .NET,如何根据文件签名而不是扩展名找到文件的 mime 类型

如何在不基于扩展的 IOS 中获取 Mime 类型

从文件扩展名中获取 MIME 类型