Visit our Sponsor   Visit our Sponsor
delphi3000.com - the free delphi knowledge platform
delphi3000.com - the free delphi knowledge platform
494 Users Online NOW
Have a look at your member-status

connecting people's knowledge


  - Recent ArticlesRSS feed for Recent Articles on delphi3000.com
  - List of All Articles
  - Top Viewed Articles
  - Articles (+Attachem.)
  - Articles Of Interest
  - Categories
  - Top Uploader
  - Search
  - Index

  - My Home
  - Submit an Article
  - My Articles
  - My Personal Data
  - My Bookmarks
  - Activities
  - Login/Logout

  - Sign Up
  - Why Sign Up
  - Newsletter

  - Press
  - Advertise

  - Contact
  - Feedback





Community
Borland
ClubeDelphi
Dr. Bob
UK-BUG
Delphi Meetings
Planeta Delphi







Startblatt.de






Share this article with friendsShare this article with friends
Rate this articleRate this article - to keep the quality of delphi3000.com !
Comment this article or read through previous comments (0)


A simple File Comparison UtilityFormat this article printer-friendly!Bookmark function is only available for registered users!
How to tell when to files are NOT the same
Product:
Delphi 3.x (or higher)
Category:
Algorithm
Skill Level:
Scoring:
Last Update:
01/19/2001
Search Keys:
delphi delphi3000 article borland vcl code-snippet Utility Comparison Differences
Times Scored:
2
Visits:
2806
Uploader: david bolton
Company:
Reference: N/A
 
Question/Problem/Abstract:
Sometimes you are only interested in knowing if two files are the same- you might have hit return a few times in the editor so one looks bigger than the other and has a later save date but it might be the same otherwise...
Answer:



The utility listed below (both .pas and .dfm source) accepts as input two file names. For convenience these filenames (with associated paths) are saved out between runs and you can copy the filename from the first box to the second (click the red down arrow) - it combines the first filename with the existing 2nd path.  Both edit boxes allow you to browse for files.

File comparison is simple and fast. Each file is read into a memory stream and then a count of each of the 256 possible characters is made. You could argue that by cutting and moving text elsewhere in a text file file that this would break my method (as char counts would be unaffected) and you'd be right but I think for most purposes this method is probably sufficient and it works with binary as well as text files. I realise a CRC calculation could also be added- feel free to do so.

When there are differences the output is a string showing each character value (0-255) followed by the count in brackets.

For something thrown together quickly in an hour or so, it has served me well and compares files of a few megabytes pretty quickly.

Pascal Source
unit viewdiff;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Buttons;

type
  TDBDiff = class
    Ffilename1 : string;
    FfileName2 : string;
    FBuff1     : TmemoryStream;
    FBuff2     : TmemoryStream;
    FCounts1    : array[0..255] of integer;
    FCounts2    : array[0..255] of integer;
    FProcessed : boolean;
    fDifferenceStr : string;
    FDifferent: boolean;
  private

    function  GetDiffCount(ch: char): integer;
    function  GetDifferences: boolean;
    procedure Clear;
    procedure BuildDiffTable(Mem1,Mem2 : pointer;size1,size2:integer);
    procedure BuildDifferenceStr;
    function  CheckIfSame: boolean;
    public
      Constructor Create;
      Destructor  Destroy;override;
      property    Different : boolean read GetDifferences;
      property    DifferenceStr : string read fDifferenceStr;
      property    DiffCount[ch : char] : integer read GetDiffCount;
      property    Filename1 : string read FFilename1 write FFilename1;
      property    Filename2 : string read FFilename2 write FFilename2;
end; // TdbDiff

TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    fileopen: TOpenDialog;
    Edit1: TEdit;
    Edit2: TEdit;
    GoBtn: TButton;
    btnCopyDown: TBitBtn;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure GoBtnClick(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnCopyDownClick(Sender: TObject);
  private
    procedure CheckGoBtn;
    procedure LoadEditBoxes;
    procedure SaveEditBoxes;
    { Private declarations }
  public
    { Public declarations }
    Aftercreate : boolean;
    Diff        : tDbDiff;
    StartPath   : string;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

Const
  editsavefilename = 'diff.ini';
  CrLf = #13#10;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if Edit1.Text <> '' then
    FileOpen.Initialdir := ExtractFileDir(Edit1.Text);
  if FileOpen.execute then
    edit1.Text := FileOpen.Filename;
  CheckGobtn;
end;


procedure Tform1.checkGoBtn;
var filename :string;
begin
  Gobtn.enabled := false;
  Filename := trim(Edit1.Text);
  if (Filename <>'') and fileexists(Filename) then
    begin
      Filename := trim(Edit2.Text);
      if (Filename <>'') and fileexists(Filename) then
        GoBtn.Enabled := True;
    end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  if Edit2.Text <> '' then
    FileOpen.Initialdir := ExtractFileDir(Edit2.Text);
  if FileOpen.execute then
    edit2.Text := FileOpen.Filename;
  CheckGoBtn;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Aftercreate := true;
end;

{ TDBDiff }

procedure TdbDiff.Clear;
begin
  fFilename1 := '';
  fFilename2 := '';
  fillchar(fCounts1,sizeof(fcounts1),0);
  fillchar(fCounts2,sizeof(fcounts2),0);
  fDifferenceStr := '';
  fProcessed := false;
end;

constructor TDBDiff.Create;
begin
  fBuff1 := TmemoryStream.Create;
  fBuff2 := TmemoryStream.Create;
  Clear;
end;

destructor TDBDiff.Destroy;
begin
  FBuff2.Free;
  FBuff1.Free;
end;

function TDBDiff.GetDiffCount(ch: char): integer;
begin
  result := fCounts1[ord(ch)]-Fcounts2[ord(ch)];
end;

procedure TdbDiff.BuildDifferenceStr;
var Index : integer;
begin
  fDifferenceStr := '';
  for Index := 0 to 255 do
    if fcounts1[Index]<> fCounts2[Index] then
       begin
         fDifferenceStr := fDifferencestr +
           ' #'+inttostr(Index)+'('+inttostr(fcounts1[Index]-Fcounts2[Index])+')';
       end;
end;

function TDBDiff.CheckIfSame: boolean;
var Index : integer;
begin
  result := true;
  for Index := 0 to 255 do
    if fcounts1[Index]<>fcounts2[Index] then
      begin
        Result := false;
        exit;
      end;
end;

procedure TDBDiff.BuildDiffTable(mem1,mem2 : pointer;size1,size2:integer);
type Bytemap = array[0..2000000000] of byte;
BytemapPtr = ^ByteMap;
var MapPtr : ByteMapPtr;
Index : integer;
begin
  MapPtr := ByteMapPtr(mem1);
  for Index := 0 to size1-1 do
    inc(fcounts1[MapPtr^[Index]]);
  MapPtr := ByteMapPtr(mem2);
  for Index := 0 to size2-1 do
    inc(fcounts2[MapPtr^[Index]]);
end;

function TDBDiff.GetDifferences: boolean;
var fs : TFileStream;
begin
  if fProcessed then
    Result := Fdifferent
  else
    begin
      Result := false;
      if (trim(Ffilename1) ='') or (trim(FFilename2) = '') then
        exit;
      fProcessed := true;
      fs := TfileStream.Create(fFilename1,fmOpenRead);
      fbuff1.LoadFromStream(fs);
      fs.free;
      fs := TfileStream.Create(fFilename2,fmOpenRead);
      fbuff2.LoadFromStream(fs);
      fs.free;
      BuildDiffTable(fbuff1.memory,fbuff2.memory,fbuff1.size,fbuff2.size);
      BuildDifferenceStr;
      Result := not CheckIfSame;
    end;
end;

procedure TForm1.GoBtnClick(Sender: TObject);

begin
  diff.Clear;
  diff.Filename1 := edit1.text;
  diff.Filename2 := edit2.text;
  if diff.Different then
    ShowMessage(
    'Differences between '+ Crlf +
      diff.Filename1 + Crlf +
      diff.Filename2 + Crlf + Crlf +
      diff.DifferenceStr)
  else
    ShowMessage('Files identical');
end;

procedure TForm1.FormActivate(Sender: TObject);
begin
  if AfterCreate then
    begin
      AFterCreate := false;
      diff := tdbdiff.Create;
      GetDir(0,StartPath);
      if StartPath[Length(StartPath)] <> '\' then
        StartPath := StartPath + '\';
      LoadEditBoxes;
    end;
end;


procedure Tform1.LoadEditBoxes;
var tf : textfile;
s : string;
begin
  if fileexists(StartPath+EditSaveFilename) then
    begin
      assignfile(tf,StartPath+EditSavefilename);
      reset(tf);
      try
        readln(tf,s);
        edit1.text := s;
        readln(tf,s);
        edit2.text := s;
      finally
        Closefile(Tf);
        CheckGoBtn;
      end;
    end;
end;

procedure Tform1.SaveEditBoxes;
var tf : textfile;
s : string;
begin
   assignfile(tf,StartPath+EditSavefilename);
   rewrite(tf);
   try
     s := edit1.text;
     writeln(tf,s);
     s := edit2.text;
     writeln(tf,s);
   finally
     Closefile(Tf);
   end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  SaveEditBoxes;
end;

procedure TForm1.btnCopyDownClick(Sender: TObject);
begin
  edit2.text := ExtractFileDir(Edit2.Text)+ '\' +
                ExtractFileName(Edit1.Text);
end;

end.

.DFM Source

object Form1: TForm1
  Left = 338
  Top = 555
  Width = 462
  Height = 172
  Caption = 'Difference Utility'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  OnActivate = FormActivate
  OnCreate = FormCreate
  OnDestroy = FormDestroy
  PixelsPerInch = 96
  TextHeight = 13
  object Button1: TButton
    Left = 12
    Top = 30
    Width = 75
    Height = 25
    Caption = '1st File'
    TabOrder = 0
    OnClick = Button1Click
  end
  object Button2: TButton
    Left = 12
    Top = 78
    Width = 75
    Height = 25
    Caption = '2nd File'
    TabOrder = 1
    OnClick = Button2Click
  end
  object Edit1: TEdit
    Left = 96
    Top = 30
    Width = 343
    Height = 21
    Anchors = [akLeft, akTop, akRight]
    TabOrder = 2
  end
  object Edit2: TEdit
    Left = 96
    Top = 78
    Width = 343
    Height = 21
    Anchors = [akLeft, akTop, akRight]
    TabOrder = 3
  end
  object GoBtn: TButton
    Left = 96
    Top = 114
    Width = 75
    Height = 25
    Caption = 'Compare'
    Enabled = False
    TabOrder = 4
    OnClick = GoBtnClick
  end
  object btnCopyDown: TBitBtn
    Left = 240
    Top = 54
    Width = 26
    Height = 23
    TabOrder = 5
    OnClick = btnCopyDownClick
    Glyph.Data = {
      76010000424D7601000000000000760000002800000020000000100000000100
      0400000000000001000000000000000000001000000010000000000000000000
      800000800000008080008000000080008000808000007F7F7F00BFBFBF000000
      FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00333333303333
      333333333337F33333333333333033333333333333373F333333333333090333
      33333333337F7F33333333333309033333333333337373F33333333330999033
      3333333337F337F33333333330999033333333333733373F3333333309999903
      333333337F33337F33333333099999033333333373333373F333333099999990
      33333337FFFF3FF7F33333300009000033333337777F77773333333333090333
      33333333337F7F33333333333309033333333333337F7F333333333333090333
      33333333337F7F33333333333309033333333333337F7F333333333333090333
      33333333337F7F33333333333300033333333333337773333333}
    NumGlyphs = 2
  end
  object fileopen: TOpenDialog
    DefaultExt = '*'
    Filter = 'Any File|*.*'
    Left = 354
  end
end






Please rate this article!
Skill level:
BeginnerExpert

Useful:
No!Very!

Overall rating:
PoorExcellent



Comments to this article
Write a new comment













 
Sign up to consume product discounts for Bronze memberships !

read more


  Visit our Sponsor

 

  Community Ad of
M. Shkolnik
 
   














 







     
  Copyright © 2000 - 2007 delphi3000.com - All rights reserved. Terms of use. || Privacy
delphi3000.com is a service by bluestep.com IT-Services GmbH (Vienna)