Subversion Repositories indexer_suite

Rev

Rev 2 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 2 Rev 4
1
unit RedundancyForm;
1
unit RedundancyForm;
2
 
2
 
-
 
3
// TODO: man soll einstellen können, dass er redundanzen nur innerhalb eines datenträgers (= root node) findet
-
 
4
 
3
interface
5
interface
4
 
6
 
5
uses
7
uses
6
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
8
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
7
  System.Classes, Vcl.Graphics, AdoDb,
9
  System.Classes, Vcl.Graphics, AdoDb,
8
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Samples.Gauges;
10
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Samples.Gauges;
9
 
11
 
10
type
12
type
11
  TfrmRedundancy = class(TForm)
13
  TfrmRedundancy = class(TForm)
12
    Button1: TButton;
14
    Button1: TButton;
13
    Memo1: TMemo;
15
    Memo1: TMemo;
14
    Gauge1: TGauge;
16
    Gauge1: TGauge;
15
    Edit1: TEdit;
17
    Edit1: TEdit;
16
    Label1: TLabel;
18
    Label1: TLabel;
17
    Label2: TLabel;
19
    Label2: TLabel;
18
    ComboBox1: TComboBox;
20
    ComboBox1: TComboBox;
19
    Label3: TLabel;
21
    Label3: TLabel;
20
    Label4: TLabel;
22
    Label4: TLabel;
21
    procedure Button1Click(Sender: TObject);
23
    procedure Button1Click(Sender: TObject);
22
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
24
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
23
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
25
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
24
    procedure FormShow(Sender: TObject);
26
    procedure FormShow(Sender: TObject);
25
  private
27
  private
26
    procedure Mode2Rec(StartDir: string; const FileMask: string;
28
    procedure Mode2Rec(StartDir: string; const FileMask: string;
27
      var cntRedundant: integer; var cntUnique: integer);
29
      var cntRedundant: integer; var cntUnique: integer);
28
  protected
30
  protected
29
    StopRequest: Boolean;
31
    StopRequest: Boolean;
30
    procedure EnableDisableControls(v: Boolean);
32
    procedure EnableDisableControls(v: Boolean);
31
    function TableName: string;
33
    function TableName: string;
32
    function conn: TAdoConnection;
34
    function conn: TAdoConnection;
33
  end;
35
  end;
34
 
36
 
35
implementation
37
implementation
36
 
38
 
37
{$R *.dfm}
39
{$R *.dfm}
38
 
40
 
39
uses
41
uses
40
  DB, AdoConnHelper, IdHashMessageDigest, idHash, MainForm, IniFiles;
42
  DB, AdoConnHelper, IdHashMessageDigest, idHash, MainForm, IniFiles;
41
 
43
 
42
function MD5File(const FileName: string): string;
44
function MD5File(const FileName: string): string;
43
var
45
var
44
  IdMD5: TIdHashMessageDigest5;
46
  IdMD5: TIdHashMessageDigest5;
45
  FS: TFileStream;
47
  FS: TFileStream;
46
begin
48
begin
47
  IdMD5 := TIdHashMessageDigest5.Create;
49
  IdMD5 := TIdHashMessageDigest5.Create;
48
  FS := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
50
  FS := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
49
  try
51
  try
50
{$IFDEF UNICODE} // I actually do not know at which version of Delphi/Indy, this has changed.
52
{$IFDEF UNICODE} // I actually do not know at which version of Delphi/Indy, this has changed.
51
    Result := IdMD5.HashStreamAsHex(FS);
53
    Result := IdMD5.HashStreamAsHex(FS);
52
{$ELSE}
54
{$ELSE}
53
    Result := IdMD5.AsHex(IdMD5.HashValue(FS));
55
    Result := IdMD5.AsHex(IdMD5.HashValue(FS));
54
{$ENDIF}
56
{$ENDIF}
55
  finally
57
  finally
56
    FS.Free;
58
    FS.Free;
57
    IdMD5.Free;
59
    IdMD5.Free;
58
  end;
60
  end;
59
end;
61
end;
60
 
62
 
61
procedure TfrmRedundancy.Mode2Rec(StartDir: string; const FileMask: string;
63
procedure TfrmRedundancy.Mode2Rec(StartDir: string; const FileMask: string;
62
  var cntRedundant: integer; var cntUnique: integer);
64
  var cntRedundant: integer; var cntUnique: integer);
63
 
65
 
64
  procedure CheckFile(aFilename: string);
66
  procedure CheckFile(aFilename: string);
65
  var
67
  var
66
    md5: string;
68
    md5: string;
67
  begin
69
  begin
68
    try
70
    try
69
      Label4.Caption := aFilename;
71
      Label4.Caption := aFilename;
70
      md5 := MD5File(aFilename);
72
      md5 := MD5File(aFilename);
71
      if conn.GetScalar('select count(*) from ' + TableName +
73
      if conn.GetScalar('select count(*) from ' + TableName +
72
        ' where md5hash = ' + conn.SQLStringEscape(md5)) = 0 then
74
        ' where md5hash = ' + conn.SQLStringEscape(md5)) = 0 then
73
      begin
75
      begin
74
        Memo1.Lines.Add(aFilename);
76
        Memo1.Lines.Add(aFilename);
75
        Inc(cntUnique);
77
        Inc(cntUnique);
76
      end
78
      end
77
      else
79
      else
78
      begin
80
      begin
79
        Inc(cntRedundant);
81
        Inc(cntRedundant);
80
      end;
82
      end;
81
    except
83
    except
82
      on E: Exception do
84
      on E: Exception do
83
      begin
85
      begin
84
        Memo1.Lines.Add(Format('Error: Cannot process %s : %s',
86
        Memo1.Lines.Add(Format('Error: Cannot process %s : %s',
85
          [aFilename, E.Message]))
87
          [aFilename, E.Message]))
86
      end;
88
      end;
87
    end;
89
    end;
88
  end;
90
  end;
89
 
91
 
90
var
92
var
91
  SR: TSearchRec;
93
  SR: TSearchRec;
92
  DirList: TStrings;
94
  DirList: TStrings;
93
  IsFound: Boolean;
95
  IsFound: Boolean;
94
  i: integer;
96
  i: integer;
95
begin
97
begin
96
  StartDir := IncludeTrailingPathDelimiter(StartDir);
98
  StartDir := IncludeTrailingPathDelimiter(StartDir);
97
 
99
 
98
  i := 0;
100
  i := 0;
99
  IsFound := FindFirst(StartDir + FileMask, faAnyFile - faDirectory, SR) = 0;
101
  IsFound := FindFirst(StartDir + FileMask, faAnyFile - faDirectory, SR) = 0;
100
  try
102
  try
101
    while IsFound do
103
    while IsFound do
102
    begin
104
    begin
103
      Inc(i);
105
      Inc(i);
104
      Application.ProcessMessages;
106
      Application.ProcessMessages;
105
      if Application.Terminated or StopRequest then
107
      if Application.Terminated or StopRequest then
106
        Abort;
108
        Abort;
107
 
109
 
108
      CheckFile(StartDir + SR.Name);
110
      CheckFile(StartDir + SR.Name);
109
      IsFound := FindNext(SR) = 0;
111
      IsFound := FindNext(SR) = 0;
110
    end;
112
    end;
111
  finally
113
  finally
112
    FindClose(SR);
114
    FindClose(SR);
113
  end;
115
  end;
114
 
116
 
115
  // Build a list of subdirectories
117
  // Build a list of subdirectories
116
  DirList := TStringList.Create;
118
  DirList := TStringList.Create;
117
  try
119
  try
118
    IsFound := FindFirst(StartDir + '*', faDirectory, SR) = 0;
120
    IsFound := FindFirst(StartDir + '*', faDirectory, SR) = 0;
119
    try
121
    try
120
      while IsFound do
122
      while IsFound do
121
      begin
123
      begin
122
        if (SR.Name <> '.') and (SR.Name <> '..') then
124
        if (SR.Name <> '.') and (SR.Name <> '..') then
123
        begin
125
        begin
124
          Application.ProcessMessages;
126
          Application.ProcessMessages;
125
          if Application.Terminated or StopRequest then
127
          if Application.Terminated or StopRequest then
126
            Abort;
128
            Abort;
127
 
129
 
128
          DirList.Add(StartDir + SR.Name);
130
          DirList.Add(StartDir + SR.Name);
129
        end;
131
        end;
130
        IsFound := FindNext(SR) = 0;
132
        IsFound := FindNext(SR) = 0;
131
      end;
133
      end;
132
    finally
134
    finally
133
      FindClose(SR);
135
      FindClose(SR);
134
    end;
136
    end;
135
 
137
 
136
    // Scan the list of subdirectories
138
    // Scan the list of subdirectories
137
    for i := 0 to DirList.Count - 1 do
139
    for i := 0 to DirList.Count - 1 do
138
    begin
140
    begin
139
      try
141
      try
140
        Mode2Rec(DirList[i], FileMask, cntRedundant, cntUnique);
142
        Mode2Rec(DirList[i], FileMask, cntRedundant, cntUnique);
141
      except
143
      except
142
        on E: Exception do
144
        on E: Exception do
143
        begin
145
        begin
144
          if E is EAbort then
146
          if E is EAbort then
145
            Abort;
147
            Abort;
146
          Memo1.Lines.Add('Unexpected error at directory ' + DirList[i] + ': ' +
148
          Memo1.Lines.Add('Unexpected error at directory ' + DirList[i] + ': ' +
147
            E.Message);
149
            E.Message);
148
        end;
150
        end;
149
      end;
151
      end;
150
    end;
152
    end;
151
  finally
153
  finally
152
    DirList.Free;
154
    DirList.Free;
153
  end;
155
  end;
154
end;
156
end;
155
 
157
 
156
function TfrmRedundancy.TableName: string;
158
function TfrmRedundancy.TableName: string;
157
begin
159
begin
158
  result := frmMain.TableName;
160
  result := frmMain.TableName;
159
end;
161
end;
160
 
162
 
161
procedure TfrmRedundancy.Button1Click(Sender: TObject);
163
procedure TfrmRedundancy.Button1Click(Sender: TObject);
162
var
164
var
163
  q: TADODataSet;
165
  q: TADODataSet;
164
  fMD5: TField;
166
  fMD5: TField;
165
  fFilename: TField;
167
  fFilename: TField;
166
  dirMask: string;
168
  dirMask: string;
167
  cntRedundant: integer;
169
  cntRedundant: integer;
168
  cntUnique: integer;
170
  cntUnique: integer;
169
begin
171
begin
170
  EnableDisableControls(False);
172
  EnableDisableControls(False);
171
  if ComboBox1.ItemIndex = 1 then
173
  if ComboBox1.ItemIndex = 1 then
172
    Gauge1.Visible := False;
174
    Gauge1.Visible := False;
173
  Memo1.Lines.Clear;
175
  Memo1.Lines.Clear;
174
  try
176
  try
175
{$REGION 'Mode 1'}
177
{$REGION 'Mode 1'}
176
    if ComboBox1.ItemIndex = 0 then
178
    if ComboBox1.ItemIndex = 0 then
177
    begin
179
    begin
178
      dirMask := IncludeTrailingPathDelimiter(Edit1.Text) + '%';
180
      dirMask := IncludeTrailingPathDelimiter(Edit1.Text) + '%';
179
      q := conn.GetTable
181
      q := conn.GetTable
180
        ('select filename, md5hash from '+TableName+' where filename like ' +
182
        ('select filename, md5hash from '+TableName+' where filename like ' +
181
        conn.SQLStringEscape(dirMask) + ' order by filename');
183
        conn.SQLStringEscape(dirMask) + ' order by filename');
182
      try
184
      try
183
        Gauge1.MinValue := 0;
185
        Gauge1.MinValue := 0;
184
        Gauge1.MaxValue := q.RecordCount;
186
        Gauge1.MaxValue := q.RecordCount;
185
        Gauge1.Progress := 0;
187
        Gauge1.Progress := 0;
186
        cntRedundant := 0;
188
        cntRedundant := 0;
187
        cntUnique := 0;
189
        cntUnique := 0;
188
        fMD5 := q.FieldByName('md5hash');
190
        fMD5 := q.FieldByName('md5hash');
189
        fFilename := q.FieldByName('filename');
191
        fFilename := q.FieldByName('filename');
190
        while not q.Eof do
192
        while not q.Eof do
191
        begin
193
        begin
192
          if conn.GetScalar('select count(*) from '+TableName+' where md5hash = ' +
194
          if conn.GetScalar('select count(*) from '+TableName+' where md5hash = ' +
193
            conn.SQLStringEscape(fMD5.AsString) + ' and filename not like ' +
195
            conn.SQLStringEscape(fMD5.AsString) + ' and filename not like ' +
194
            conn.SQLStringEscape(dirMask)) = 0 then
196
            conn.SQLStringEscape(dirMask)) = 0 then
195
          begin
197
          begin
196
            Memo1.Lines.Add(fFilename.AsString);
198
            Memo1.Lines.Add(fFilename.AsString);
197
            Inc(cntUnique);
199
            Inc(cntUnique);
198
          end
200
          end
199
          else
201
          else
200
          begin
202
          begin
201
            Inc(cntRedundant);
203
            Inc(cntRedundant);
202
          end;
204
          end;
203
          Gauge1.Progress := Gauge1.Progress + 1;
205
          Gauge1.Progress := Gauge1.Progress + 1;
204
          Application.ProcessMessages;
206
          Application.ProcessMessages;
205
          if Application.Terminated then
207
          if Application.Terminated then
206
            Abort;
208
            Abort;
207
          q.Next;
209
          q.Next;
208
        end;
210
        end;
209
      finally
211
      finally
210
        q.Free;
212
        q.Free;
211
      end;
213
      end;
212
    end;
214
    end;
213
{$ENDREGION}
215
{$ENDREGION}
214
{$REGION 'Mode 2'}
216
{$REGION 'Mode 2'}
215
    if ComboBox1.ItemIndex = 1 then
217
    if ComboBox1.ItemIndex = 1 then
216
    begin
218
    begin
217
      cntRedundant := 0;
219
      cntRedundant := 0;
218
      cntUnique := 0;
220
      cntUnique := 0;
219
      Mode2Rec(Edit1.Text, '*', cntRedundant, cntUnique);
221
      Mode2Rec(Edit1.Text, '*', cntRedundant, cntUnique);
220
    end;
222
    end;
221
{$ENDREGION}
223
{$ENDREGION}
222
    if (cntRedundant = 0) and (cntUnique = 0) then
224
    if (cntRedundant = 0) and (cntUnique = 0) then
223
      raise Exception.Create('No files found. Is the string correct?')
225
      raise Exception.Create('No files found. Is the string correct?')
224
    else
226
    else
225
      ShowMessageFmt('Done. %d files are redundant. %d are unique.',
227
      ShowMessageFmt('Done. %d files are redundant. %d are unique.',
226
        [cntRedundant, cntUnique]);
228
        [cntRedundant, cntUnique]);
227
 
229
 
228
    if ComboBox1.ItemIndex = 0 then
230
    if ComboBox1.ItemIndex = 0 then
229
    begin
231
    begin
230
      ShowMessage
232
      ShowMessage
231
        ('Attention: Only check 1 directory at a time, then delete redundant files, then re-index and only then continue with checking the redundancy of the any other directory.');
233
        ('Attention: Only check 1 directory at a time, then delete redundant files, then re-index and only then continue with checking the redundancy of the any other directory.');
232
    end;
234
    end;
233
  finally
235
  finally
234
    EnableDisableControls(True);
236
    EnableDisableControls(True);
235
    Gauge1.Progress := 0;
237
    Gauge1.Progress := 0;
236
    Gauge1.Visible := True;
238
    Gauge1.Visible := True;
237
    Label4.Caption := '';
239
    Label4.Caption := '';
238
  end;
240
  end;
239
end;
241
end;
240
 
242
 
241
function TfrmRedundancy.conn: TAdoConnection;
243
function TfrmRedundancy.conn: TAdoConnection;
242
begin
244
begin
243
  Result := frmMain.AdoConnection1;
245
  Result := frmMain.AdoConnection1;
244
end;
246
end;
245
 
247
 
246
procedure TfrmRedundancy.EnableDisableControls(v: Boolean);
248
procedure TfrmRedundancy.EnableDisableControls(v: Boolean);
247
begin
249
begin
248
  Edit1.Enabled := v;
250
  Edit1.Enabled := v;
249
  Button1.Enabled := v;
251
  Button1.Enabled := v;
250
  ComboBox1.Enabled := v;
252
  ComboBox1.Enabled := v;
251
end;
253
end;
252
 
254
 
253
procedure TfrmRedundancy.FormClose(Sender: TObject; var Action: TCloseAction);
255
procedure TfrmRedundancy.FormClose(Sender: TObject; var Action: TCloseAction);
254
begin
256
begin
255
  Action := caFree;
257
  Action := caFree;
256
end;
258
end;
257
 
259
 
258
procedure TfrmRedundancy.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
260
procedure TfrmRedundancy.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
259
begin
261
begin
260
  StopRequest := True;
262
  StopRequest := True;
261
end;
263
end;
262
 
264
 
263
procedure TfrmRedundancy.FormShow(Sender: TObject);
265
procedure TfrmRedundancy.FormShow(Sender: TObject);
264
var
266
var
265
  ini: TMemIniFile;
267
  ini: TMemIniFile;
266
begin
268
begin
267
  ini := frmMain.ini;
269
  ini := frmMain.ini;
268
  Edit1.Text := ini.ReadString('RedundancyFinder', 'DefaultDir', '');
270
  Edit1.Text := ini.ReadString('RedundancyFinder', 'DefaultDir', '');
269
  ComboBox1.ItemIndex := ini.ReadInteger('RedundancyFinder', 'DefaultMode', 1)-1;
271
  ComboBox1.ItemIndex := ini.ReadInteger('RedundancyFinder', 'DefaultMode', 1)-1;
270
end;
272
end;
271
 
273
 
272
end.
274
end.
273
 
275