यह है कि आप विभिन्न तरीकों से मिश्रण कर रहे हैं ReadDirectoryChangesW() उपयोग करने के लिए मुझे लगता है, आप दोनों फ़ाइल _ फ्लैग _ ओवरलैप झंडा जब निर्देशिका खोलने निर्दिष्ट करें और करने के लिए lpOverlapped पैरामीटर एक सूचक प्रदान करते हैं , जिसका अर्थ है कि आप संरचना में घटना पर इंतजार करना चाहते हैं और एसिंक्रोनस I/O को संभालना चाहते हैं; और साथ ही आप कार्यकर्ता धागे में एक लूप में ReadDirectoryChangesW() पर कॉल करें। मैं पहले lpOverlappedशून्य पर फिर से प्रयास करता हूं, क्योंकि आपके पास समर्पित थ्रेड है और सिंक्रोनस मोड का उपयोग कर सकता है।
ReadDirectoryChangesW() एपीआई के दस्तावेज में इसका उपयोग करने के विभिन्न तरीकों का वर्णन किया गया है। ध्यान दें कि यह भी संभव है कि बफर ओवरफ्लो हो, इसलिए घटनाओं को बदलना वैसे भी खोया जा सकता है। शायद आपको इस फ़ंक्शन पर पूरी तरह भरोसा करने की अपनी रणनीति पर पुनर्विचार करना चाहिए, निर्देशिका सामग्री के स्नैपशॉट की तुलना करना भी काम कर सकता है।
संपादित करें:
आपके संपादित कोड बेहतर लग रहा है। मेरे परीक्षणों में हालांकि ReadDirectoryChangesW() विज्ञापन के रूप में काम करता था, लौटा बफर में कई डेटा प्रविष्टियां थीं, या प्रक्रिया करने के लिए एक से अधिक बफर थे। यह डेल्फी में ब्रेकपॉइंट मारने के बाद समय पर निर्भर करता है, मुझे एक बफर में कई प्रविष्टियां मिलती हैं।
type
TWatcherThread = class(TThread)
private
fChangeHandle: THandle;
fDirHandle: THandle;
fShutdownHandle: THandle;
protected
procedure Execute; override;
public
constructor Create(ADirectoryToWatch: string);
destructor Destroy; override;
procedure Shutdown;
end;
constructor TWatcherThread.Create(ADirectoryToWatch: string);
const
FILE_LIST_DIRECTORY = 1;
begin
inherited Create(TRUE);
fChangeHandle := CreateEvent(nil, FALSE, FALSE, nil);
fDirHandle := CreateFile(PChar(ADirectoryToWatch),
FILE_LIST_DIRECTORY or GENERIC_READ,
FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED, 0);
fShutdownHandle := CreateEvent(nil, FALSE, FALSE, nil);
Resume;
end;
destructor TWatcherThread.Destroy;
begin
if fDirHandle <> INVALID_HANDLE_VALUE then
CloseHandle(fDirHandle);
if fChangeHandle <> 0 then
CloseHandle(fChangeHandle);
if fShutdownHandle <> 0 then
CloseHandle(fShutdownHandle);
inherited Destroy;
end;
procedure TWatcherThread.Execute;
type
PFileNotifyInformation = ^TFileNotifyInformation;
TFileNotifyInformation = record
NextEntryOffset: DWORD;
Action: DWORD;
FileNameLength: DWORD;
FileName: WideChar;
end;
const
BufferLength = 65536;
var
Filter, BytesRead: DWORD;
InfoPointer: PFileNotifyInformation;
Offset, NextOffset: DWORD;
Buffer: array[0..BufferLength - 1] of byte;
Overlap: TOverlapped;
Events: array[0..1] of THandle;
WaitResult: DWORD;
FileName, s: string;
begin
if fDirHandle <> INVALID_HANDLE_VALUE then begin
Filter := FILE_NOTIFY_CHANGE_FILE_NAME or FILE_NOTIFY_CHANGE_DIR_NAME
or FILE_NOTIFY_CHANGE_SIZE or FILE_NOTIFY_CHANGE_LAST_WRITE;
FillChar(Overlap, SizeOf(TOverlapped), 0);
Overlap.hEvent := fChangeHandle;
Events[0] := fChangeHandle;
Events[1] := fShutdownHandle;
while not Terminated do begin
if ReadDirectoryChangesW (fDirHandle, @Buffer[0], BufferLength, TRUE,
Filter, @BytesRead, @Overlap, nil)
then begin
WaitResult := WaitForMultipleObjects(2, @Events[0], FALSE, INFINITE);
if WaitResult = WAIT_OBJECT_0 then begin
InfoPointer := @Buffer[0];
Offset := 0;
repeat
NextOffset := InfoPointer.NextEntryOffset;
FileName := WideCharLenToString(@InfoPointer.FileName,
InfoPointer.FileNameLength);
SetLength(FileName, StrLen(PChar(FileName)));
s := Format('[%d] Action: %.8xh, File: "%s"',
[Offset, InfoPointer.Action, FileName]);
OutputDebugString(PChar(s));
PByte(InfoPointer) := PByte(DWORD(InfoPointer) + NextOffset);
Offset := Offset + NextOffset;
until NextOffset = 0;
end;
end;
end;
end;
end;
procedure TWatcherThread.Shutdown;
begin
Terminate;
if fShutdownHandle <> 0 then
SetEvent(fShutdownHandle);
end;
////////////////////////////////////////////////////////////////////////////////
procedure TForm1.FormCreate(Sender: TObject);
begin
fThread := TWatcherThread.Create('D:\Temp');
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
if fThread <> nil then begin
TWatcherThread(fThread).Shutdown;
fThread.Free;
end;
end;
एक निर्देशिका हटाया जा रहा है वास्तव में केवल इसके लिए एक परिवर्तन, उसमें शामिल फ़ाइलों के लिए कुछ भी नहीं लौट करता है:
पूर्णता के लिए मैं परीक्षण कोड देते हैं, डेल्फी 5 का उपयोग कर कार्यान्वित किया। लेकिन यह समझ में आता है, क्योंकि आप केवल मूल निर्देशिका के हैंडल देख रहे हैं। अगर आपको उपनिर्देशिका के लिए अधिसूचनाओं की आवश्यकता है तो आपको शायद उन्हें भी देखना होगा।
मेरी देरी टिप्पणी के लिए खेद है।मैंने पहले सिंक्रोनस संस्करण का उपयोग किया (ठीक उसी समस्या के साथ) लेकिन एसिंक्रोनस संस्करण में स्विच किया क्योंकि मुझे धागे को साफ करने के लिए कोई रास्ता नहीं मिला। मुझे उदाहरण कोड में एक महत्वपूर्ण पंक्ति याद आई है (हालांकि WaitForMultipleObjects को अवरुद्ध कॉल, जिसे या तो फ़ाइल परिवर्तन ईवेंट द्वारा समाप्त किया जा सकता है या एक समाप्ति घटना द्वारा)। मैं तदनुसार सवाल संपादित करता हूं। (...) – jpfollenius
स्नैपशॉट से आपका क्या मतलब है? यदि आप FindFirst का उपयोग कर सभी फाइलों पर पुनरावृत्ति का मतलब है, FindNext: मैंने पहले इस तरह के एक दृष्टिकोण का उपयोग किया था, लेकिन मैं बड़ी निर्देशिकाओं का उपयोग करते समय (1) बड़ी पहचान का समय और (2) इंडेक्सिंग थ्रेड के लिए स्थिर I/O लोड में देरी से बचने के लिए (1) सभी को धीमा करना चाहता था अन्य I/O संचालन। – jpfollenius
आपकी दूसरी टिप्पणी से सहमत है, लेकिन जैसा कि एमएसडीएन दस्तावेज बताता है कि आपको आंतरिक बफर के अतिप्रवाह के लिए तैयार होने की आवश्यकता है, और उस स्थिति में निर्देशिका का पूर्ण (पुनः) स्कैन आवश्यक है। – mghie