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

如何对基于ULARGE_INTEGER的Size/Date列的ListView进行排序?

Win32 ListView 文件列排序方案

针对你提到的Size和Date列排序需求,以下是高效可靠的实现方案:

一、大小列排序:避免字符串转数值的隐患

你提到用std::stoi(wstr)转换大小字符串,但要注意:std::stoi针对32位int类型,而大文件(如超过4GB)的大小会超出int范围,导致溢出错误。更稳妥的做法是直接用原始的ULONGLONG数值比较——不需要从字符串转回。

二、日期列排序:不要解析格式化后的字符串

通过SHFormatDate()生成的日期字符串是本地化的(不同区域的格式、分隔符、年月日顺序都可能不同),反向解析不仅繁琐,还容易出错。最优方案是维护原始数据的并行存储,直接用数值比较。

标准实现步骤

Win32 ListView的排序通常结合ListView_SortItemsEx和自定义比较回调,通过LVITEM的lParam关联原始数据,完全规避字符串转换问题:

1. 定义存储文件原始数据的结构体

struct FileListItemData {
    ULONGLONG fileSize;       // 原始文件大小(从WIN32_FIND_DATA组合而来)
    FILETIME fileLastWriteTime; // 原始文件时间(如最后修改时间)
    // 可添加其他需要的字段,如文件名、路径等
};

2. 添加ListView项时关联原始数据

// 假设已获取WIN32_FIND_DATA fd,hListView是ListView句柄
int nItemIndex = ListView_GetItemCount(hListView);

// 分配并填充原始数据
FileListItemData* pItemData = new FileListItemData();
// 组合文件大小
ULARGE_INTEGER sizeU;
sizeU.LowPart = fd.nFileSizeLow;
sizeU.HighPart = fd.nFileSizeHigh;
pItemData->fileSize = sizeU.QuadPart;
// 保存原始文件时间(这里选最后修改时间,可根据需求替换)
pItemData->fileLastWriteTime = fd.ftLastWriteTime;

// 插入ListView项
LVITEM lvi = {0};
lvi.mask = LVIF_TEXT | LVIF_PARAM;
lvi.iItem = nItemIndex;
lvi.pszText = const_cast<wchar_t*>(fd.cFileName); // 设置文件名
lvi.lParam = reinterpret_cast<LPARAM>(pItemData); // 关联原始数据
ListView_InsertItem(hListView, &lvi);

// 设置大小列文本
std::wstring sizeStr = std::towstring(pItemData->fileSize);
ListView_SetItemText(hListView, nItemIndex, 1, const_cast<wchar_t*>(sizeStr.c_str()));

// 设置日期列文本
wchar_t dateBuf[256] = {0};
SHFormatDate(&pItemData->fileLastWriteTime, SHFD_AUTOLAYOUT, dateBuf, ARRAYSIZE(dateBuf));
ListView_SetItemText(hListView, nItemIndex, 2, dateBuf);

3. 实现排序回调函数

int CALLBACK ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) {
    // lParamSort传递排序列索引和方向(低16位是列索引,高16位是0=升序,1=降序)
    int sortCol = LOWORD(lParamSort);
    bool isAscending = HIWORD(lParamSort) == 0;

    FileListItemData* pData1 = reinterpret_cast<FileListItemData*>(lParam1);
    FileListItemData* pData2 = reinterpret_cast<FileListItemData*>(lParam2);

    int cmpResult = 0;
    switch (sortCol) {
        case 1: // 大小列排序
            if (pData1->fileSize < pData2->fileSize) cmpResult = -1;
            else if (pData1->fileSize > pData2->fileSize) cmpResult = 1;
            break;
        case 2: // 日期列排序
            // 将FILETIME转为64位数值直接比较
            ULONGLONG time1 = reinterpret_cast<ULARGE_INTEGER&>(pData1->fileLastWriteTime).QuadPart;
            ULONGLONG time2 = reinterpret_cast<ULARGE_INTEGER&>(pData2->fileLastWriteTime).QuadPart;
            if (time1 < time2) cmpResult = -1;
            else if (time1 > time2) cmpResult = 1;
            break;
        // 其他列排序逻辑可在此扩展
    }

    // 降序时反转结果
    if (!isAscending) cmpResult = -cmpResult;
    return cmpResult;
}

4. 触发排序(如点击列头时)

// 假设点击的列索引为nCol,当前排序方向为bAscending(true=升序)
LPARAM sortParam = MAKELPARAM(nCol, bAscending ? 0 : 1);
ListView_SortItemsEx(hListView, ListViewCompareProc, sortParam);

三、关于你提到的两种方案的对比

  • 维护并行数据结构:这是Win32 ListView排序的标准实践,完全避免字符串解析的误差和性能损耗,逻辑清晰且可靠,是首选方案。
  • C++日期时间库解析字符串:由于SHFormatDate()的本地化特性,解析格式化后的日期字符串极易出错(如不同区域的格式差异),且步骤繁琐,不推荐使用。

内容的提问来源于stack exchange,提问作者gene b.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 06:37:16