Delphi - 根据大小对文件进行排序

时间:2017-06-13 06:45:15

标签: sorting delphi

我试图根据Delphi 2010中的大小对文件列表进行排序。 我已经递归地获取了所有文件大小,文件创建日期和文件位置路径,但我在排序时遇到问题。

我的结果如下:

MB 57.682(60483584) - 08-06-2017 15:03 - o:\ Thumbs.db

MB 4.217(4422144) - 08-06-2017 13:48 - o:\ bmp \ Thumbs.db

数据必须按从最大文件到最小文件的顺序排序,并将结果存储到文件中。

我使用字符串格式化人类可读形式的文件大小。

在这种情况下,正确的方法是什么? 我应该将数据存储为csv值,然后尝试对它们进行排序吗? 我应该使用字符串列表吗?

这是我正在使用的代码:

procedure FasterSubFilesList_mmg(folder, exts: string; files: TStrings);

// builds recursive list of files matching set of extensions like '.exe .txt.htm'
 function ext(filename: string): string;
  begin result:= lowercase(extractFileExt(filename));
 end;

 CONST
  SizeUnits     : ARRAY[0..8] OF PChar = ('bytes','KB','MB','GB','TB','PB','EB','ZB','YB');

FUNCTION FormatByteSize(Size : UInt64 ; Decimals : BYTE) : String; OVERLOAD;
  VAR
    I           : Cardinal;
    S           : Extended;

  BEGIN
    S:=Size;
    FOR I:=LOW(SizeUnits) TO HIGH(SizeUnits) DO BEGIN
      IF S<1024.0 THEN BEGIN
        IF I=LOW(SizeUnits) THEN Decimals:=0;
        Result:=Format('%.'+IntToStr(Decimals)+'f',[S]);
        {adaug dimensiune urmata de unitatea de masura}
        //Result:=Result+' '+StrPas(SizeUnits[I]);

        {adaug unitatea de masura urmata de dimensiune}
        Result:=StrPas(SizeUnits[I])+' '+Result;
        EXIT
      END;
      S:=S/1024.0
    END
  END;

FUNCTION FormatByteSize(Size : UInt64) : String; OVERLOAD;
  VAR
    P   : Integer;

  BEGIN
    Result:=FormatByteSize(Size,3);
    IF Size>=1024 THEN BEGIN
      P:=PRED(LastDelimiter(' ',Result));
      WHILE COPY(Result,P,1)='0' DO BEGIN
        DELETE(Result,P,1);
        DEC(P)
      END;
      IF CharInSet(Result[P],['.',',']) THEN DELETE(Result,P,1)
    END
  END;




{ functie pentru a afla dimensiunea unui fisier }
function GetFileSize_mmg(const FileName: string): Int64;
var
  fad: TWin32FileAttributeData;
begin
if not GetFileAttributesEx(PChar(FileName), GetFileExInfoStandard, @fad) then RaiseLastOSError;
  //GetFileAttributesEx(PChar(FileName), GetFileExInfoStandard, @fad);
  Int64Rec(Result).Lo := fad.nFileSizeLow;
  Int64Rec(Result).Hi := fad.nFileSizeHigh;
end;

 procedure AddFolder(dir: string);
  var F: TSearchRec;
      size:string;
      data_creare_fisier:string;
  const
   //findTypes=faArchive+faHidden+faReadOnly+faAnyFile+faDirectory;
   findTypes=faAnyFile;
  begin
   dir:= excludetrailingbackslash(dir)+'\';

   if FindFirst(dir+'*.*', findTypes, F)=0 then
   try

    repeat
     if (F.attr and faDirectory=faDirectory) then
     begin
       if (F.Name<>'.') and (F.Name<>'..') then AddFolder(dir+F.Name);

     end
     else
     if (exts='*') or (pos(ext(F.Name)+' ', exts)>0) then
     size:=FormatByteSize(GetFileSize_mmg(dir+F.name));
     shortdateformat:='dd-mm-yyyy';
     data_creare_fisier:=formatdatetime(shortdateformat+' hh:nn',filedatetodatetime(f.time));

     files.Add(size+' ('+inttostr(GetFileSize_mmg(dir+F.name))+') - '+data_creare_fisier+' - '+dir+F.Name);
     //files.Add('"'+size+'","'+inttostr(GetFileSize_mmg(dir+F.name))+'","'+data_creare_fisier+'","'+dir+F.Name+'"');
     //files.Add(inttostr(GetFileSize_mmg(dir+F.name))+' ('+size+') - '+data_creare_fisier+' - '+dir+F.Name);
    until FindNext(F)<>0;
   finally FindClose(F) end;
  end;


begin


 if (trim(exts)='') or (exts='*') or (exts='*.*') then exts:='*'
  else exts:= trim(lowercase(exts))+' ';
 files.clear;
 AddFolder(folder);
end;



procedure TForm1.Button1Click(Sender: TObject);
var
  FilesList: TStringList;
 i:integer;
    lista_descrescatoare:Tstrings;
begin
ListBox_fisiere_de_verificat.Items.Clear;


//listbox_fisiere_de_verificat.Items.BeginUpdate;
//afiseaza_in_listbox_fisiere_ce_pot_fi_procesate('O:\','*.*',true,10,listbox_fisiere_de_verificat,false,memo_loguri);
//listbox_fisiere_de_verificat.Items.EndUpdate;
memo_loguri.lines.add(FormatDatetime('dd-mm-yyyy hh:mm:ss', Now) +' - start listare fisiere');
FilesList:=Tstringlist.Create;
FilesList.Sorted:=true;
FilesList.Sort;



FasterSubFilesList_mmg('o:\','*.*',FilesList);

listbox_fisiere_de_verificat.items.AddStrings(FilesList);

memo_loguri.lines.add(' - total fisiere:'+inttostr(fileslist.count));
memo_loguri.lines.add(FormatDatetime('dd-mm-yyyy hh:mm:ss', Now) +' - stop listare fisiere');

end;

谢谢!

1 个答案:

答案 0 :(得分:2)

考虑到您已经拥有FilesList TStringList中的文件列表,您可以在那里对它们进行排序。您可以调用CustomSort方法,提供自定义比较功能以指示哪个文件大于另一个文件。

function FileGreater(FileList: TStringList; Index1: integer; Index2: integer): integer;
var IniPos1, EndPos1, IniPos2, EndPos2: integer;
    Size1, Size2: Int64; 
begin
  IniPos1 := Pos('(', FileList[Index1]) + 1;
  EndPos1 := Pos(')', FileList[Index1]) - 1;
  IniPos2 := Pos('(', FileList[Index2]) + 1;
  EndPos2 := Pos(')', FileList[Index2]) - 1;

  Size1 := StrToint64(Copy(FileList[Index1], IniPos1, EndPos1 - IniPos1));
  Size2 := StrToint64(Copy(FileList[Index2], IniPos2, EndPos2 - IniPos2));

  if Size1 = Size2 then Result := 0
  else if Size1 < Size2 then Result := -1
  else Result := 1;
end;

现在你打电话:

 FileList.CustomSort(FileGreater);     
PS:正如David Heffernan在评论中所说,StrToInt返回一个LongInt,因此它只适用于高达2Gb的文件。我已经更新了使用StrToInt64的答案,但您最好使用适当的结构来存储文件的数据而不是这个快速修复。