如何从指定位置向ListView第三列添加文件大小数据?
问题排查与修复方案
首先,你的代码核心问题是没有把文件大小对应到ListView中已有的文件条目上,而是把所有大小作为新的ListItem添加,同时还有内存管理和逻辑上的疏漏。下面一步步拆解问题并给出修复方案:
一、核心逻辑错误:文件大小与条目不匹配
原代码中,你先添加文件夹、文件条目,然后单独把大小作为新行添加,这完全不符合"第三列显示大小"的需求。正确的逻辑应该是:
- 添加文件夹条目时,第三列可以填
"-"或者空(文件夹本身无文件大小属性) - 添加文件条目时,直接把对应的大小添加到该条目的
SubItems第二个位置(第一列是名称,第二列是类型,第三列就是大小)
二、具体代码修复步骤
1. 修复全局变量ListSize的内存泄漏与逻辑错误
全局变量ListSize在GetFiles中重复创建却从未释放,会导致严重内存泄漏。我们去掉全局变量,让GetFiles通过参数传出大小列表:
function GetFiles(const FileName, Ext: String; out FileSizes: TStrings): TStrings; Var SearchFile: TSearchRec; FindResult: integer; ListFiles: TStrings; FullPath: string; begin ListFiles := TStringlist.Create; FileSizes := TStringlist.Create; FindResult := FindFirst(FileName + Ext, faAnyFile, SearchFile); try While FindResult = 0 do begin // 排除目录和.、.. if (SearchFile.Attr and faDirectory) = 0 then begin FullPath := FileName + SearchFile.Name; ListFiles.Add(SearchFile.Name); FileSizes.Add(FileSizeStr(FullPath)); end; FindResult := FindNext(SearchFile); end; finally FindClose(SearchFile) end; Result := ListFiles; end;
2. 修复ListView的填充逻辑
修改btn1Click,让文件大小对应到正确列,同时确保ListView是报表模式并添加好三列(可在设计时设置,也可代码添加):
procedure TForm1.btn1Click(Sender: TObject); var L: TListItem; vListFolders, vListFiles, vListSize: TStringlist; i: integer; begin LV1.Clear; // 确保ListView为报表模式并配置列 LV1.ViewStyle := vsReport; while LV1.Columns.Count < 3 do LV1.Columns.Add; LV1.Columns[0].Caption := '名称'; LV1.Columns[1].Caption := '类型'; LV1.Columns[2].Caption := '大小'; // 调整列宽适配显示 LV1.Columns[0].Width := 200; LV1.Columns[1].Width := 80; LV1.Columns[2].Width := 100; vListFolders := TStringlist.Create; try vListFolders.Text := ListFolders('C:\'); // 添加文件夹条目 for i := 0 to vListFolders.Count - 1 do begin L := LV1.Items.Add; L.Caption := vListFolders.Strings[i]; L.SubItems.Add('Folder'); L.SubItems.Add('-'); // 文件夹大小列显示"-" end; finally vListFolders.Free; end; vListFiles := TStringlist.Create; vListSize := TStringlist.Create; try vListFiles := GetFiles('C:\', '*.*', vListSize); // 添加文件条目并对应大小到第三列 for i := 0 to vListFiles.Count - 1 do begin L := LV1.Items.Add; L.Caption := vListFiles.Strings[i]; L.SubItems.Add('File'); L.SubItems.Add(vListSize.Strings[i]); end; finally vListFiles.Free; vListSize.Free; end; end;
3. 修复ListFolders函数的逻辑错误
原函数会包含.和..目录,且字符串拼接效率低,修改如下:
function ListFolders(const Directory: String): string; var SearchRec: TWin32FindData; FindHandle: THandle; Dirlist: TStrings; begin Dirlist := TStringList.Create; try FindHandle := FindFirstFile(PChar(Directory + '*.*'), SearchRec); if FindHandle <> INVALID_HANDLE_VALUE then begin repeat // 仅保留真实目录,排除.和.. if ((SearchRec.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) <> 0) and (SearchRec.cFileName <> '.') and (SearchRec.cFileName <> '..') then begin Dirlist.Add(SearchRec.cFileName); end; until not FindNextFile(FindHandle, SearchRec); Winapi.Windows.FindClose(FindHandle); end; Result := Dirlist.Text; finally Dirlist.Free; end; end;
4. 优化FileSizeStr函数的显示精度
原函数用%f会显示过多小数位,改为保留两位小数更美观,同时添加文件共享模式避免占用报错:
function FileSizeStr(const FileName: string): string; const K = Int64(1024); M = K * K; G = K * M; T = K * G; var size: Int64; handle: integer; begin handle := FileOpen(FileName, fmOpenRead or fmShareDenyNone); if handle = -1 then Result := '无法打开文件' else try size := FileSeek(handle, Int64(0), 2); if size < K then Result := Format('%d bytes', [size]) else if size < M then Result := Format('%.2f KB', [size / K]) else if size < G then Result := Format('%.2f MB', [size / M]) else if size < T then Result := Format('%.2f GB', [size / G]) else Result := Format('%.2f TB', [size / T]); finally FileClose(handle); end; end;
三、结合远程场景的适配建议
根据你补充的远程管理应用逻辑,需确保文件名和大小的顺序完全对应,接收完数据后填充ListView时,把每个文件条目对应的大小添加到第三列:
// 假设已接收解析得到文件列表FileList和大小列表SizeList for i := 0 to FileList.Count - 1 do begin L := (L2.SubItems.Objects[4] as TForm3).ListView1.Items.Add; L.ImageIndex := 1; // 设置文件图标索引 L.Caption := FileList.Strings[i]; L.SubItems.Add('File'); if i < SizeList.Count then L.SubItems.Add(SizeList.Strings[i]) else L.SubItems.Add('未知'); end;
这样就能确保每个文件条目第三列显示对应的大小了。
内容的提问来源于stack exchange,提问作者user9672569
相关产品推荐
相关产品推荐

