• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 194
  • Last Modified:

Detect File Changes in Dir

How can i detect if a File have changed in a special directory (I mean a new File, a File was deleted . . . .)
And how can i detect if a SubFolder was changed ?
0
snoopy_Spy
Asked:
snoopy_Spy
1 Solution
 
daniel_cCommented:
You can use TTimer to detect it.
I give you an example:
1. Make New Application from Delphi IDE.
2. Add component TFileListBox
3. Add Component TTimer

On Form Event Create, put this code:
procedure TForm1.FormCreate(Sender: TObject);
begin
  FileListBox1.Directory:= 'C:\';
end;

On TTimer Event Timer, put this code:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  FileListBox1.Update;
end;


Below is the whole code:
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    FileListBox1: TFileListBox;
    Timer1: TTimer;
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  CanClose:= false;
  ShowMessage('Sorry, cannot close!');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FileListBox1.Directory:= 'C:\';
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  FileListBox1.Update;
end;

end.

It will always update information on folder C:\.

Hope it will help!

Regards,

Daniel
0
 
MadshiCommented:
Under win9x you can use FindFirstFileNotification, but this API only tells you that *something* has happened, it doesn't tell you the filename etc.
Under winNT you can use ReadDirectoryChangesW, which tells you all you want to know.

Regards, Madshi.
0
 
AswCommented:
Listening.
0
Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
snoopy_SpyAuthor Commented:
Sorry but this is not the way i would like to make it !

Madshi
Have you some further infos about the two functions ?
0
 
MadshiCommented:
Hmmm... There's a component in the free RxLibrary for FindFirstFileNotification. Look here:

http://www.rxlib.com/

I've nothing for ReadDirectoryChangesW, sorry.

Regards, Madshi.
0
 
mullet_attackCommented:
here's a component I wrote some years ago, so I can't remember a lot about it, but it provides a changed event if the montitored directory changes. I can also monitor subdirectories, and allows you to specify what you'd like to monitor.

Anyway, have a look at it and see if it's what you want.

unit changed;

interface

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

type
  EChangeError = class(exception);

  TChangeSet = (ntFileName, ntDirName, ntAttributes, ntSize, ntLastWrite, ntSecurity);
  TChangeType = set of TChangeSet;

  TChanged = class;

  TWaitThread = class(TThread)
  private
    EventArray:array[0..1] of THandle;
    fNotifyType : DWORD;
    fChanged : TChanged;
  protected
    Procedure Execute;override;
  public
    Constructor Create(NotifyType:DWORD;Changed:TChanged);
  end;

  TChanged = class(TComponent)
  private
    fEnabled : boolean;
    fSubDirs : boolean;
    fPath : string;
    fChangeType : TChangeType;
    fLocalChangeType : DWORD;
    fWaitThread : TWaitThread;
    szPath : array[0..255] of char;
    fOnChanged : TNotifyEvent;
    procedure UpdateThread;
  protected
    procedure SetEnabled(value:boolean);
    procedure SetSubDirs(value:boolean);
    procedure SetPath(value:string);
    procedure SetChangeType(value:TChangeType);
    procedure DoChanged;
  public
    Constructor Create(AOwner:TComponent);override;
    Destructor Destroy;override;
  published
    Property Enabled:boolean read fEnabled write SetEnabled;
    Property SubDirs:boolean read fSubDirs write SetSubDirs;
    Property OnChanged:TNotifyEvent read fOnChanged write fOnChanged;
    Property ChangeType:TChangeType read fChangeType write SetChangeType;
    Property Path:string read fPath write SetPath;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Planetech', [TChanged]);
end;

Constructor TWaitThread.Create(NotifyType:DWORD;Changed:TChanged);
begin
  inherited Create(False);
  fNotifyType := NotifyType;
  fChanged := Changed;
end;

procedure TWaitThread.Execute;
begin
  while not Terminated do with (fChanged as TChanged) do
    begin
      EventArray[0] := CreateEvent(Nil,    // no security attributes
                                   TRUE,    // manual reset event
                                   FALSE,   // not-signalled
                                   Nil);   // no name
      EventArray[1] := FindFirstChangeNotification(szPath,
                                                   fSubDirs,
                                                   fNotifyType);
      WaitForMultipleObjects(2, @EventArray, FALSE, INFINITE);
      synchronize(doChanged);

      FindCloseChangeNotification(EventArray[1]);
      CloseHandle(EventArray[0]);
    end;
end;
//----------------------------------------------------------------------------

Constructor TChanged.Create(AOwner:TComponent);
var
  t:integer;
begin
  inherited Create(AOwner);
end;

Destructor TChanged.Destroy;
begin
  inherited Destroy;
end;

procedure TChanged.SetEnabled(value:boolean);
begin
  if value = fEnabled then exit;
  fEnabled := value;
  UpdateThread;
end;

procedure TChanged.SetSubDirs(value:boolean);
begin
  if value = fSubDirs then exit;
  fSubDirs := value;
  UpdateThread;
end;

procedure TChanged.SetPath(value:string);
begin
  if value = fPath then exit;
  fPath := value;
  StrPCopy(szPath, fPath);
  UpdateThread;
end;

procedure TChanged.SetChangeType(value:TChangeType);
begin
  if fChangeType = value then exit;
  fLocalChangeType := 0;
  if ntFileName in value then fLocalChangeType := fLocalChangeType or FILE_NOTIFY_CHANGE_FILE_NAME;
  if ntDirName in value then fLocalChangeType := fLocalChangeType or FILE_NOTIFY_CHANGE_DIR_NAME;
  if ntAttributes in value then fLocalChangeType := fLocalChangeType or FILE_NOTIFY_CHANGE_ATTRIBUTES;
  if ntSize in value then fLocalChangeType := fLocalChangeType or FILE_NOTIFY_CHANGE_SIZE;
  if ntLastWrite in value then fLocalChangeType := fLocalChangeType or FILE_NOTIFY_CHANGE_LAST_WRITE;
  if ntSecurity in value then fLocalChangeType := fLocalChangeType or FILE_NOTIFY_CHANGE_SECURITY;
  fChangeType := value;
end;

procedure TChanged.UpdateThread;
begin
  if (not (csDesigning in ComponentState) and (fPath = '')) then
      Raise EChangeError.create('Path cannot be Null');
  if (not (csDesigning in ComponentState) and (fLocalChangeType = 0)) then
      Raise EChangeError.create('Must Specify ChangeType');
  if fWaitThread <> nil then
     begin
       fWaitThread.Terminate;
       PulseEvent(fWaitThread.EventArray[0]);
       WaitForSingleObject(fWaitThread.handle, INFINITE);
       CloseHandle(fWaitThread.handle);
       fWaitThread := nil;
     end;
  if fEnabled then
    fWaitThread := TWaitThread.create(fLocalChangeType,self);
end;

procedure TChanged.DoChanged;
begin
  if assigned (fOnChanged) then fOnChanged(Self);
end;

end.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now