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

如何从ITEMIDLIST(pidl)快速获取文件大小及修改日期?

问题

我看到许多实现资源管理器样式视图的示例,这类实现的核心问题是速度,瓶颈在于文件大小的获取——当前需额外调用接口获取文件状态(修改日期与文件大小),代码实现如下:

case static_cast<int>(Columns::SizeColumn): //deliberate fallthrough
case static_cast<int>(Columns::DateModifiedColumn):
{
  CString sPath;
  CFileStatus fs;
  if (pItem->m_pidlFQ.ToPath(sPath) && CFile::GetStatus(sPath, fs))
  {
    CString sText;
    if (nColumn == static_cast<int>(Columns::SizeColumn))
    {
      if ((fs.m_attribute & (CFile::directory | CFile::volume)) == 0)
        OnFormatFileSize(fs.m_size, sText);
    }
    else
      OnFormatFileDate(fs.m_mtime, sText);
    return sText;
  }
  break;
}

但这种方式速度较慢,是否存在更简便的方法直接从pidl获取文件修改日期与大小?

回答

当然有更高效的方案,无需将PIDL转换为路径再调用CFile::GetStatus,直接通过Shell原生接口从PIDL提取所需信息,能大幅提升性能:

方法1:使用SHGetFileInfo API

这是Win32原生的Shell API,支持直接从PIDL获取文件大小、修改日期等属性,跳过路径转换步骤:

case static_cast<int>(Columns::SizeColumn): //deliberate fallthrough
case static_cast<int>(Columns::DateModifiedColumn):
{
    SHFILEINFO sfi = {0};
    UINT flags = SHGFI_PIDL; // 指定输入为PIDL
    
    if (nColumn == static_cast<int>(Columns::SizeColumn))
    {
        flags |= SHGFI_SIZESIZE; // 请求文件大小
    }
    else
    {
        flags |= SHGFI_ATTRIBUTES; // 先获取属性判断类型
    }

    if (SHGetFileInfo((LPCVOID)pItem->m_pidlFQ, 0, &sfi, sizeof(sfi), flags))
    {
        CString sText;
        if (nColumn == static_cast<int>(Columns::SizeColumn))
        {
            // 组合高低位得到64位文件大小
            ULONGLONG fileSize = (static_cast<ULONGLONG>(sfi.nFileSizeHigh) << 32) | sfi.nFileSizeLow;
            // 排除目录和卷
            if (!(sfi.dwAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_VOLUME)))
                OnFormatFileSize(fileSize, sText);
        }
        else
        {
            // 通过IShellFolder获取修改日期
            IShellFolder* pParentFolder = nullptr;
            LPITEMIDLIST pidlRelative = nullptr;
            if (SUCCEEDED(SHBindToParent(pItem->m_pidlFQ, IID_IShellFolder, (void**)&pParentFolder, &pidlRelative)))
            {
                FILETIME ftModified = {0};
                if (SUCCEEDED(pParentFolder->GetDetailsOf(pidlRelative, SHCOL_INDEX_DATE_MODIFIED, &ftModified)))
                {
                    SYSTEMTIME stLocal;
                    FileTimeToSystemTime(&ftModified, &stLocal);
                    OnFormatFileDate(stLocal, sText);
                }
                pParentFolder->Release();
                CoTaskMemFree(pidlRelative);
            }
        }
        return sText;
    }
    break;
}

方法2:使用现代IShellItem2接口

这是Windows Vista及以后推荐的Shell接口,支持通过属性键直接获取文件元数据,代码更简洁且性能更优:

case static_cast<int>(Columns::SizeColumn): //deliberate fallthrough
case static_cast<int>(Columns::DateModifiedColumn):
{
    IShellItem2* pShellItem = nullptr;
    if (SUCCEEDED(SHCreateItemFromIDList(pItem->m_pidlFQ, IID_IShellItem2, (void**)&pShellItem)))
    {
        CString sText;
        if (nColumn == static_cast<int>(Columns::SizeColumn))
        {
            ULONGLONG fileSize = 0;
            DWORD dwAttrs = 0;
            // 获取文件大小和属性
            if (SUCCEEDED(pShellItem->GetFileAttributesAndSize(&dwAttrs, &fileSize)))
            {
                // 排除目录和卷
                if (!(dwAttrs & (SFGAO_FOLDER | SFGAO_VOLUME)))
                    OnFormatFileSize(fileSize, sText);
            }
        }
        else
        {
            PROPVARIANT pvDate = {0};
            if (SUCCEEDED(pShellItem->GetValue(PKEY_DateModified, &pvDate)))
            {
                SYSTEMTIME stLocal;
                FileTimeToSystemTime(&pvDate.filetime, &stLocal);
                OnFormatFileDate(stLocal, sText);
                PropVariantClear(&pvDate);
            }
        }
        pShellItem->Release();
        return sText;
    }
    break;
}

性能提升原因

  • 跳过PIDL转文件路径的额外开销,直接操作Shell内部数据结构
  • 利用Shell缓存的元数据,避免重复访问文件系统
  • 减少系统调用次数,批量获取属性时优势更明显

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 10:55:26