Delphi 如何递归地检测对文件的更改?
我正在开发一个多线程组件来加载和管理音乐库,我有一个属性定义了要包含的多个根目录。一个线程搜索这些目录中的媒体文件,根据需要添加/删除,另一个线程遍历这些文件并填写ID3v2标记信息。我已经有了检测添加/删除文件的机制,但我不知道如何检测更改Delphi 如何递归地检测对文件的更改?,delphi,delphi-xe2,id3v2,Delphi,Delphi Xe2,Id3v2,我正在开发一个多线程组件来加载和管理音乐库,我有一个属性定义了要包含的多个根目录。一个线程搜索这些目录中的媒体文件,根据需要添加/删除,另一个线程遍历这些文件并填写ID3v2标记信息。我已经有了检测添加/删除文件的机制,但我不知道如何检测更改 如何检测其他外部应用程序何时对这些文件进行了更改?我想要即时响应,而不必等待线程访问该文件。当这些文件夹中的任何文件被递归更改时,是否有一种方法可以接收警报?您需要使用的功能是。这不是世界上最容易使用的功能,值得指出的是,它不是100%可靠的。它有时无法通
如何检测其他外部应用程序何时对这些文件进行了更改?我想要即时响应,而不必等待线程访问该文件。当这些文件夹中的任何文件被递归更改时,是否有一种方法可以接收警报?您需要使用的功能是。这不是世界上最容易使用的功能,值得指出的是,它不是100%可靠的。它有时无法通知您修改。根据我的经验,这种情况更可能发生在股票上 此API可以在同步或异步模式下使用。与往常一样,同步版本更容易编码。但它当然会阻止调用线程。因此,解决方法是在不同的线程中调用
ReadDirectoryChangesW
。如果要监视大量目录,那么每个目录一个监视线程将是一个不可行的负担。如果是这样的话,那么您需要解决异步使用问题
YoubWatchSubtree
参数允许您监视整个目录树,我认为这是您想要做的
有关更多详细信息,请参阅本文: 试试这个:
uses
ShlObj, ActiveX;
const
FILE_LIST_DIRECTORY = $0001;
cDir = 'E:\...'; // The directory to monitor
Type
PFileNotifyInformation = ^TFileNotifyInformation;
TFileNotifyInformation = Record
NextEntryOffset: DWORD;
Action: DWORD;
FileNameLength: DWORD;
FileName: Array[0..0] of WideChar;
End;
type
TWaitThread = class(TThread)
private
FForm: TMainForm;
procedure HandleEvent;
protected
procedure Execute; override;
public
constructor Create(Form: TMainForm);
Procedure SendFtp(F: String; AddIfError: Boolean);
end;
procedure TWaitThread.HandleEvent;
Var
FileOpNotification: PFileNotifyInformation;
Offset: Longint;
F: String;
AList: TStringList;
I: Integer;
begin
AList := TStringList.Create;
Try
With FForm Do
Begin
Pointer(FileOpNotification) := @FNotificationBuffer[0];
Repeat
Offset := FileOpNotification^.NextEntryOffset;
//lbEvents.Items.Add(Format(SAction[FileOpNotification^.Action], [WideCharToString(@(FileOpNotification^.FileName))]));
F := cDir + WideCharToString(@(FileOpNotification^.FileName));
if AList.IndexOf(F) < 0 Then
AList.Add(F);
PChar(FileOpNotification) := PChar(FileOpNotification)+Offset;
Until Offset=0;
For I := 0 To AList.Count -1 Do
// do whatever you need
End;
Finally
AList.Free;
End;
end;
constructor TWaitThread.Create(Form: TMainForm);
begin
inherited Create(True);
FForm := Form;
FreeOnTerminate := False;
end;
procedure TWaitThread.Execute;
Var
NumBytes: DWORD;
CompletionKey: DWORD;
begin
While Not Terminated Do
Begin
GetQueuedCompletionStatus( FForm.FCompletionPort, numBytes, CompletionKey, FForm.FPOverlapped, INFINITE);
if CompletionKey <> 0 Then
Begin
Synchronize(HandleEvent);
With FForm do
begin
FBytesWritten := 0;
ZeroMemory(@FNotificationBuffer, SizeOf(FNotificationBuffer));
ReadDirectoryChanges(FDirectoryHandle, @FNotificationBuffer, SizeOf(FNotificationBuffer), False, FNotifyFilter, @FBytesWritten, @FOverlapped, nil);
End;
End
Else
Terminate;
End;
end;
{MainForm}
private
FDirectoryHandle: THandle;
FNotificationBuffer: array[0..4096] of Byte;
FWatchThread: TThread;
FNotifyFilter: DWORD;
FOverlapped: TOverlapped;
FPOverlapped: POverlapped;
FBytesWritten: DWORD;
FCompletionPort: THandle;
procedure TMainForm.FormCreate(Sender: TObject);
begin
FCompletionPort := 0;
FDirectoryHandle := 0;
FPOverlapped := @FOverlapped;
ZeroMemory(@FOverlapped, SizeOf(FOverlapped));
Start;
end;
procedure TMainForm.Start;
begin
FNotifyFilter := 0;
FNotifyFilter := FNotifyFilter or FILE_NOTIFY_CHANGE_FILE_NAME;
FDirectoryHandle := CreateFile(cDir,
FILE_LIST_DIRECTORY,
FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
Nil,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED,
0);
if FDirectoryHandle = INVALID_HANDLE_VALUE Then
Begin
Beep;
FDirectoryHandle := 0;
ShowMessage(SysErrorMessage(GetLastError));
Exit;
End;
FCompletionPort := CreateIoCompletionPort(FDirectoryHandle, 0, Longint(pointer(self)), 0);
ZeroMemory(@FNotificationBuffer, SizeOf(FNotificationBuffer));
FBytesWritten := 0;
if Not ReadDirectoryChanges(FDirectoryHandle, @FNotificationBuffer, SizeOf(FNotificationBuffer), False, FNotifyFilter, @FBytesWritten, @FOverlapped, Nil) Then
Begin
CloseHandle(FDirectoryHandle);
FDirectoryHandle := 0;
CloseHandle(FCompletionPort);
FCompletionPort := 0;
ShowMessage(SysErrorMessage(GetLastError));
Exit;
End;
FWatchThread := TWaitThread.Create(self);
TWaitThread(FWatchThread).Resume;
end;
procedure TMainForm.Stop;
begin
if FCompletionPort = 0 Then
Exit;
PostQueuedCompletionStatus(FCompletionPort, 0, 0, Nil);
FWatchThread.WaitFor;
FWatchThread.Free;
CloseHandle(FDirectoryHandle);
FDirectoryHandle := 0;
CloseHandle(FCompletionPort);
FCompletionPort := 0;
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
Stop;
end;
使用
ShlObj,ActiveX;
常数
文件列表目录=$0001;
cDir='E:\…';//要监视的目录
类型
PFileNotifyInformation=^TFileNotifyInformation;
TFileNotifyInformation=记录
下一个偏移量:DWORD;
行动:德沃德;
文件名长度:DWORD;
文件名:WideChar的数组[0..0];
结束;
类型
TWaitThread=class(TThread)
私有的
FForm:tma通知;
程序句柄;
受保护的
程序执行;推翻
公众的
建造商创建(表格:TMainForm);
过程SendFtp(F:String;AddIfError:Boolean);
结束;
程序TWaitThread.HandleEvent;
变量
FileOpNotification:PFileNotifyInformation;
偏移量:长;
F:字符串;
作者:TStringList;
I:整数;
开始
AList:=TStringList.Create;
尝试
带着我做的
开始
指针(FileOpNotification):=@FNotificationBuffer[0];
重复
偏移量:=FileOpNotification^.NextEntryOffset;
//添加(格式(SAction[FileOpNotification^.Action],[WideCharToString(@(FileOpNotification^.FileName)));
F:=cDir+WideCharToString(@(FileOpNotification^.FileName));
如果列表索引F(F)<0,则
3.添加(F);
PChar(FileOpNotification):=PChar(FileOpNotification)+偏移量;
直到偏移量=0;
对于I:=0到AList.Count-1 Do
//你需要什么就做什么
结束;
最后
免费的;
结束;
结束;
构造函数TWaitThread.Create(形式:TMainForm);
开始
继承创建(True);
FForm:=形式;
FreeOnTerminate:=False;
结束;
过程TWaitThread.Execute;
变量
NumBytes:德沃德;
完成键:DWORD;
开始
虽然没有终止
开始
GetQueuedCompletionStatus(FForm.fcCompletionPort,numBytes,CompletionKey,FForm.FPOverlapped,无限);
如果CompletionKey为0,则
开始
同步(HandleEvent);
带着我做的
开始
fBytesWrited:=0;
零内存(@FNotificationBuffer,SizeOf(FNotificationBuffer));
ReadDirectoryChanges(FDirectoryHandle、@FNotificationBuffer、SizeOf(FNotificationBuffer)、False、FNotifyFilter、@fBytesWrite、@FOverlapped、nil);
结束;
终点
其他的
终止
结束;
结束;
{MainForm}
私有的
董事会主席:唐德尔;
FNotificationBuffer:字节的数组[0..4096];
FWatchThread:TThread;
FNotifyFilter:DWORD;
FOverlapped:TOverlapped;
FP重叠:POverlapped;
fBytes:德沃德;
F完成端口:坦德尔;
程序TMAInformCreate(发送方:ToObject);
开始
FCompletionPort:=0;
FDirectoryHandle:=0;
FPOverlapped:=@FOverlapped;
零内存(@FOverlapped,SizeOf(FOverlapped));
开始
结束;
程序启动;
开始
FNotifyFilter:=0;
FNotifyFilter:=FNotifyFilter或FILE\u NOTIFY\u CHANGE\u FILE\u NAME;
FDirectoryHandle:=CreateFile(cDir,
文件列表目录,
文件共享读取或文件共享写入或文件共享删除,
无
开放式,
文件\u标志\u备份\u语义或文件\u标志\u重叠,
0);
如果FDirectoryHandle=无效的句柄值,则
开始
嘟嘟声
FDirectoryHandle:=0;
ShowMessage(SysErrorMessage(GetLastError));
出口
结束;
fcCompletionPort:=CreateIoCompletionPort(FDirectoryHandle,0,Longint(指针(自身)),0);
零内存(@FNotificationBuffer,SizeOf(FNotificationBuffer));
fBytesWrited:=0;
如果没有ReadDirectoryChanges(FDirectoryHandle、@FNotificationBuffer、SizeOf(FNotificationBuffer)、False、FNotifyFilter、@fBytesWrite、@FOverlapped、Nil),则
开始
CloseHandle(FDirectoryHandle);
FDirectoryHandle:=0;
关闭手柄(FCompletionPort);
FCompletionPort:=0;
ShowMessage(SysErrorMessage(GetLastError));
出口
结束;
FWatchThread:=TWaitThread.Create(self);
TWaitThread(FWatchThread).继续;
结束;
程序。停止;
开始
如果FCompletionPort=0,则
出口
PostQueuedCompletionStatus(FCompletionPort,0,0,Nil);
FWatchThread.WaitFor;
免费的;
CloseHandle(FDirectoryHandle);
FDirectoryHandle:=0;
关闭手柄(FCompletionPort);
FCompletionPort:=0;
结束;
程序TMAInformDestroy(发送方:TObject);
开始
停止
结束;
谢谢,我可以做