2005. február 6., vasárnap

How to compare the contents of folders including subdirectories


Problem/Question/Abstract:

I need to compare the file contents of a folder and its subfolders on all Win98 machines at my client's site (each machine was setup differently but, over time, has had different patches applied to the program in question). I need to report back only the differences found in files based upon Time/ Date stamp. Is there a good way to do this?

Answer:

You use a recursive scanning loop (FindFirst/ FindNext/ FindClose) starting at the topmost folder you need to examine. The loop stores each file it find into a TStringlist. It stores a relative path to the start folder. For each file found it also stores the searchrec.time into the Objects property of the stringlist (it uses AddObject instead of Add). It will fit with a little typecast since it is four bytes, like an object reference. After the end of the scan you have a list of all files, which you can now write to disk for your reference computer to produce a master list that will be used on the other PCs to find the differences. The output file needs to contain the timestamp, of course, so it would be produced with something like:

procedure SaveScan(files: TStringlist; const filename: string);
var
  f: textfile;
  i: Integer;
begin
  assignfile(f, filename);
  rewrite(f);
  try
    for i = 0 to files.count - 1 do
      writeLn(f, Format('%p%s', [pointer(files.Objects[i]), files[i]]));
  finally
    closefile(f);
  end;
end;

Reading the list back would be:

procedure LoadScan(files: TStringlist; const filename: string);
var
  f: textfile;
  S: string;
begin
  assignfile(f, filename);
  reset(f);
  try
    files.clear;
    while not EOF(f) do
    begin
      ReadLn(f, S);
      files.AddObject(Copy(S, 9, Maxint), TObject(StrToInt('$' + Copy(S, 1, 8))));
    end;
  finally
    Closefile(f);
  end;
end;

Ok, on the other PCs you repeat the scan to build the list of files on that PC, you load the master list into another TStringlist, sort both lists and then compare them item by item. How complex that can get depends on what kinds of differences you expect to find. If there can be missing and extra files in addition to changed ones it gets a bit intricate but not too daunting. It goes like this:

You define two counters for the two lists, lets call them mi for the master list and li for the "local" list to compare it to. Both start out at 0.

while (mi < masterlist.count) do
begin
  if masterlist[mi] = locallist[li] then
  begin
    {compare the two objects properties, if not equal report the file as changed}
    Inc(mi);
    Inc(li);
  end
  else if masterlist[mi] < locallist[li] then
  begin
    {report masterlist[mi] as missing}
    Inc(mi);
  end
  else
  begin
    {report locallist[li] as extra}
    Inc(li);
  end;
  if mi >= masterlist.count then
    {report any remaining files in locallist as extra}
    if li >= locallist.count then
      {report any remaining files in masterlist as missing and increment mi for each,
                         so the loop is terminated}
end;

Nincsenek megjegyzések:

Megjegyzés küldése