1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
| program projectgeneric;
{$mode objfpc}{$H+}
uses
Classes, SysUtils, FGL;
type
TDirectoryNode = class;
TDirectoryNodeList = class;
// Classe représentant un nud de répertoire
TDirectoryNode = class
private
FSize: Int64;
FChildren: TDirectoryNodeList;
FPath: string;
public
constructor Create(const aPath: string = '');
destructor Destroy; override;
procedure BuildFromPath;
property Path: string read FPath write FPath;
property Size: Int64 read FSize write FSize;
property Children: TDirectoryNodeList read FChildren;
end;
TDirectoryNodeCompare = function(const A, B: TDirectoryNode): Integer;
// Liste de TDirectoryNode avec tri récursif
TDirectoryNodeList = class(specialize TFPGObjectList<TDirectoryNode>)
public
procedure SortRecursive(aComparer: TDirectoryNodeCompare; const aReverse: Boolean);
end;
// Comparateur de taille
TDirNodeSortBySize = class
public
class function Compare(constref i1, i2: TDirectoryNode): Integer; static;
end;
constructor TDirectoryNode.Create(const aPath: string);
begin
inherited Create;
FChildren := TDirectoryNodeList.Create(True);
FPath := aPath;
FSize := 0;
end;
destructor TDirectoryNode.Destroy;
begin
FChildren.Free;
inherited Destroy;
end;
procedure TDirectoryNode.BuildFromPath;
var
SR: TSearchRec;
SubNode: TDirectoryNode;
FilePath: string;
begin
if not DirectoryExists(FPath) then
Exit;
if FindFirst(IncludeTrailingPathDelimiter(FPath) + '*', faAnyFile and not faVolumeID, SR) = 0 then
begin
repeat
if (SR.Name = '.') or (SR.Name = '..') then
Continue;
FilePath := IncludeTrailingPathDelimiter(FPath) + SR.Name;
if (SR.Attr and faDirectory) <> 0 then
begin
// Répertoire : créer un sous-nud et récursion
SubNode := TDirectoryNode.Create(FilePath);
SubNode.BuildFromPath;
FChildren.Add(SubNode);
Inc(FSize, SubNode.Size);
end
else
begin
// Fichier : ajouter la taille
Inc(FSize, SR.Size);
end;
until FindNext(SR) <> 0;
FindClose(SR);
end;
end;
function CompareBySize(const A, B: TDirectoryNode): Integer;
begin
if A.Size < B.Size then
Result := -1
else if A.Size > B.Size then
Result := 1
else
Result := 0;
end;
function CompareBySizeDescending(const A, B: TDirectoryNode): Integer;
begin
Result := -CompareBySize(A, B);
end;
procedure TDirectoryNodeList.SortRecursive(aComparer: TDirectoryNodeCompare; const aReverse: Boolean);
var
i: Integer;
begin
if aReverse then
Sort(@CompareBySizeDescending)
else
Sort(@CompareBySize);
// Appel récursif
for i := 0 to Count - 1 do
Items[i].Children.SortRecursive(aComparer, aReverse);
end;
class function TDirNodeSortBySize.Compare(constref i1, i2: TDirectoryNode): Integer;
begin
if i1.Size < i2.Size then
Result := -1
else if i1.Size > i2.Size then
Result := 1
else
Result := 0;
end;
procedure PrintDirectoryTree(Node: TDirectoryNode; Level: Integer = 0);
var
i: Integer;
begin
WriteLn(StringOfChar(' ', Level * 2), ExtractFileName(Node.Path), ' (', Node.Size, ' bytes)');
for i := 0 to Node.Children.Count - 1 do
PrintDirectoryTree(Node.Children[i], Level + 1);
end;
var
Root: TDirectoryNode;
begin
Writeln('Start');
Root := TDirectoryNode.Create('D:\tmp'); // À adapter
Root.BuildFromPath;
// Trier les répertoires et sous-répertoires par taille décroissante
Root.Children.SortRecursive(@CompareBySize, True);
PrintDirectoryTree(Root);
// Libération
Root.Free;
Readln;
end. |
Partager