I
import
Unregistered / Unconfirmed
GUEST, unregistred user!
问题:我想知道一个文件是否被改变,如何监视?一个方法是使用Timer不停监测,这样不精确并且来非CPU时间,那么有没有更好的方法呢? 来自Luke有:
TFileChangeNotificationStatus=(fnsIdle,fnsError,fnsRunning);
TFileChangeNotification=record
PathName:string;
WatchSubtree:boolean;
NotifyFilterWORD;
Status:TFileChangeNotificationStatus;
ChangesWORD;
wndHandle:HWND;
NotificationMessageWORD;
end;
TFileChangesMultipleWatcher = class(TThread)
private
{ Private declarations }
FMutex:integer;
FObjectsArray:array[0..(WAITOBJECTSCOUNT-1)]of integer;
protected
procedure Execute; override;
public
Notification:TFileChangeNotification;
constructor Create(Suspended:boolean);
destructor Destroy; override;
procedure Init;
procedure Stop;
end;
constructor TFileChangesMultipleWatcher.Create;
var guid:TGUID;
begin
inherited;
coCreateGuid(guid);
FMutex:=CreateMutex(nil,False,PChar('TFCMW.'+GuidToString(guid)));
WaitForSingleObject(FMutex,INFINITE);
if FMutex<>0 then FObjectsArray[0]:=FMutex;
FreeOnTerminate:=True;
end;
//
destructor TFileChangesMultipleWatcher.Destroy;
begin
inherited;
{$ifdef DEBUGGING_FILECHANGES} writeln(Notification.PathName,' -DESTROY'); {$endif}
end;
//
procedure TFileChangesMultipleWatcher.Init;
begin
with Notification do begin
PathName:='';
WatchSubtree:=False;
NotifyFilter:=0;
Status:=fnsIdle;
Changes:=0;
wndHandle:=0;
NotificationMessage:=WM_USER;
end;
end;
//
procedure TFileChangesMultipleWatcher.Stop;
begin
Terminate;
ReleaseMutex(FMutex);
end;
//
procedure TFileChangesMultipleWatcher.Execute;
var WaitStatus,hChangesWORD;
Go:boolean;
begin
try while (not Terminated) do begin
with Notification do begin
hChanges:=FindFirstChangeNotification(PChar(PathName),WatchSubtree,NotifyFil
ter);
{$ifdef DEBUGGING_FILECHANGES} writeln('Notification Handle is
',hChanges); {$endif}
if (hChanges<>INVALID_HANDLE_VALUE) then try
FObjectsArray[1]:=hChanges;
Status:=fnsRunning;
Go:=True;
while (Go) do begin
{$ifdef DEBUGGING_FILECHANGES} writeln('WaitForSingleObject');
{$endif}
WaitStatus:=WaitForMultipleObjects(WAITOBJECTSCOUNT,@FObjectsArray,False,INF
INITE);
file://if Terminated then exit;
case WaitStatus of
WAIT_ABANDONED:begin
{$ifdef DEBUGGING_FILECHANGES} writeln('WAIT_ABANDONED');
{$endif}
end;
WAIT_OBJECT_0:begin
exit;
{$ifdef DEBUGGING_FILECHANGES} writeln('WAIT_OBJECT_0');
{$endif}
end;
WAIT_OBJECT_0+1:begin
inc(Changes);
if (wndHandle<>0) then
PostMessage(wndHandle,NotificationMessage,Changes,NotificationMessage+Change
s);
{$ifdef DEBUGGING_FILECHANGES} writeln('WAIT_OBJECT_1');
{$endif}
end;
WAIT_TIMEOUT:begin
{$ifdef DEBUGGING_FILECHANGES} writeln('WAIT_TIMEOUT');
{$endif}
end;
end;
Sleep(100);
Go:=FindNextChangeNotification(hChanges);
end;
finally
{$ifdef DEBUGGING_FILECHANGES} writeln('FINALLY 1'); {$endif}
FindCloseChangeNotification(hChanges);
end else begin
Status:=fnsError;
{$ifdef DEBUGGING_FILECHANGES} writeln('STATUS ERROR'); {$endif}
end;
end;
end;
finally
{$ifdef DEBUGGING_FILECHANGES} writeln('FINALLY 2'); {$endif}
ReleaseMutex(FMutex);
end;
{$ifdef DEBUGGING_FILECHANGES} writeln('BYE!'); {$endif}
end;
//
TFileChangeNotificationStatus=(fnsIdle,fnsError,fnsRunning);
TFileChangeNotification=record
PathName:string;
WatchSubtree:boolean;
NotifyFilterWORD;
Status:TFileChangeNotificationStatus;
ChangesWORD;
wndHandle:HWND;
NotificationMessageWORD;
end;
TFileChangesMultipleWatcher = class(TThread)
private
{ Private declarations }
FMutex:integer;
FObjectsArray:array[0..(WAITOBJECTSCOUNT-1)]of integer;
protected
procedure Execute; override;
public
Notification:TFileChangeNotification;
constructor Create(Suspended:boolean);
destructor Destroy; override;
procedure Init;
procedure Stop;
end;
constructor TFileChangesMultipleWatcher.Create;
var guid:TGUID;
begin
inherited;
coCreateGuid(guid);
FMutex:=CreateMutex(nil,False,PChar('TFCMW.'+GuidToString(guid)));
WaitForSingleObject(FMutex,INFINITE);
if FMutex<>0 then FObjectsArray[0]:=FMutex;
FreeOnTerminate:=True;
end;
//
destructor TFileChangesMultipleWatcher.Destroy;
begin
inherited;
{$ifdef DEBUGGING_FILECHANGES} writeln(Notification.PathName,' -DESTROY'); {$endif}
end;
//
procedure TFileChangesMultipleWatcher.Init;
begin
with Notification do begin
PathName:='';
WatchSubtree:=False;
NotifyFilter:=0;
Status:=fnsIdle;
Changes:=0;
wndHandle:=0;
NotificationMessage:=WM_USER;
end;
end;
//
procedure TFileChangesMultipleWatcher.Stop;
begin
Terminate;
ReleaseMutex(FMutex);
end;
//
procedure TFileChangesMultipleWatcher.Execute;
var WaitStatus,hChangesWORD;
Go:boolean;
begin
try while (not Terminated) do begin
with Notification do begin
hChanges:=FindFirstChangeNotification(PChar(PathName),WatchSubtree,NotifyFil
ter);
{$ifdef DEBUGGING_FILECHANGES} writeln('Notification Handle is
',hChanges); {$endif}
if (hChanges<>INVALID_HANDLE_VALUE) then try
FObjectsArray[1]:=hChanges;
Status:=fnsRunning;
Go:=True;
while (Go) do begin
{$ifdef DEBUGGING_FILECHANGES} writeln('WaitForSingleObject');
{$endif}
WaitStatus:=WaitForMultipleObjects(WAITOBJECTSCOUNT,@FObjectsArray,False,INF
INITE);
file://if Terminated then exit;
case WaitStatus of
WAIT_ABANDONED:begin
{$ifdef DEBUGGING_FILECHANGES} writeln('WAIT_ABANDONED');
{$endif}
end;
WAIT_OBJECT_0:begin
exit;
{$ifdef DEBUGGING_FILECHANGES} writeln('WAIT_OBJECT_0');
{$endif}
end;
WAIT_OBJECT_0+1:begin
inc(Changes);
if (wndHandle<>0) then
PostMessage(wndHandle,NotificationMessage,Changes,NotificationMessage+Change
s);
{$ifdef DEBUGGING_FILECHANGES} writeln('WAIT_OBJECT_1');
{$endif}
end;
WAIT_TIMEOUT:begin
{$ifdef DEBUGGING_FILECHANGES} writeln('WAIT_TIMEOUT');
{$endif}
end;
end;
Sleep(100);
Go:=FindNextChangeNotification(hChanges);
end;
finally
{$ifdef DEBUGGING_FILECHANGES} writeln('FINALLY 1'); {$endif}
FindCloseChangeNotification(hChanges);
end else begin
Status:=fnsError;
{$ifdef DEBUGGING_FILECHANGES} writeln('STATUS ERROR'); {$endif}
end;
end;
end;
finally
{$ifdef DEBUGGING_FILECHANGES} writeln('FINALLY 2'); {$endif}
ReleaseMutex(FMutex);
end;
{$ifdef DEBUGGING_FILECHANGES} writeln('BYE!'); {$endif}
end;
//