You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中使用SHGetFileInfo获取文件属性:ListView添加创建时间与大小

解决SHGetFileInfo结合ListView获取图标、文件类型及文件元数据的问题

我来帮你理清这里的关键点——首先得澄清一个常见误解:SHGetFileInfo本身并不直接返回文件的创建时间和大小,SHGFI_ATTR_SPECIFIED标志是用来筛选文件系统属性(比如只读、隐藏、系统文件这类),而非文件的元数据(时间、大小)。不过我们可以在同一流程里,用SHGetFileInfo拿图标和文件类型,同时配合你已经在遍历的FileInfo对象获取时间和大小,这样既满足需求又高效。

第一步:确保结构体和API声明正确

先把C#里需要的SHFILEINFO结构体和Win32 API导入写对:

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;

[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;
}

public static class Shell32
{
    [DllImport("shell32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern bool DestroyIcon(IntPtr hIcon);

    // 定义需要的标志位
    public const uint SHGFI_ICON = 0x100;
    public const uint SHGFI_DISPLAYNAME = 0x200;
    public const uint SHGFI_SMALLICON = 0x1;
    public const uint SHGFI_ATTRIBUTES = 0x800;
    public const uint SHGFI_ATTR_SPECIFIED = 0x2000;
    public const uint FILE_ATTRIBUTE_READONLY = 0x1;
}

第二步:修正你的循环代码

在遍历文件的循环里,我们先调用SHGetFileInfo获取图标和文件类型,再直接用FileInfo拿创建时间和大小,最后把所有信息添加到ListView:

// 假设你已经初始化了ListView和对应的ImageList
// listView1.LargeImageList = imageList1; // 或者用SmallImageList

DirectoryInfo dir = new DirectoryInfo(@"C:\Your\Target\Directory");
foreach (FileInfo file in dir.EnumerateFiles())
{
    SHFILEINFO shfi = new SHFILEINFO();

    // 调用SHGetFileInfo获取图标和文件类型
    IntPtr result = Shell32.SHGetFileInfo(
        file.FullName,
        0,
        ref shfi,
        (uint)Marshal.SizeOf(shfi),
        Shell32.SHGFI_ICON | Shell32.SHGFI_DISPLAYNAME | Shell32.SHGFI_SMALLICON
    );

    if (result != IntPtr.Zero)
    {
        // 将图标添加到ImageList(记得只添加一次,避免重复)
        if (!imageList1.Images.ContainsKey(file.Extension))
        {
            imageList1.Images.Add(file.Extension, Icon.FromHandle(shfi.hIcon));
            // 释放系统分配的图标资源,避免内存泄漏
            Shell32.DestroyIcon(shfi.hIcon);
        }

        // 准备ListView项
        ListViewItem item = new ListViewItem(file.Name);
        item.SubItems.Add(shfi.szTypeName); // 文件类型
        item.SubItems.Add(file.CreationTime.ToString("yyyy-MM-dd HH:mm:ss")); // 创建时间
        item.SubItems.Add(FormatFileSize(file.Length)); // 格式化文件大小
        item.ImageKey = file.Extension; // 关联ImageList里的图标

        listView1.Items.Add(item);
    }
}

// 辅助方法:格式化文件大小为易读格式
private string FormatFileSize(long bytes)
{
    string[] sizes = { "B", "KB", "MB", "GB" };
    double len = bytes;
    int order = 0;
    while (len >= 1024 && order < sizes.Length - 1)
    {
        order++;
        len /= 1024;
    }
    return $"{len:0.##} {sizes[order]}";
}

关于SHGFI_ATTR_SPECIFIED的正确用法

如果你的需求里确实需要判断文件的系统属性(比如是否只读、隐藏),可以结合SHGFI_ATTRIBUTES和SHGFI_ATTR_SPECIFIED来实现,比如:

// 检查文件是否为只读
uint targetAttr = Shell32.FILE_ATTRIBUTE_READONLY;
IntPtr attrResult = Shell32.SHGetFileInfo(
    file.FullName,
    targetAttr,
    ref shfi,
    (uint)Marshal.SizeOf(shfi),
    Shell32.SHGFI_ATTRIBUTES | Shell32.SHGFI_ATTR_SPECIFIED
);

bool isReadOnly = (shfi.dwAttributes & targetAttr) != 0;

关键总结

  • SHGetFileInfo的核心能力是获取Shell相关信息(图标、显示名称),文件元数据(时间、大小)用FileInfo获取更直接高效;
  • 记得手动释放SHGetFileInfo返回的图标句柄,避免内存泄漏;
  • SHGFI_ATTR_SPECIFIED是用来筛选特定的文件系统属性,而非获取文件元数据。

内容的提问来源于stack exchange,提问作者Lucy82

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:05:03