2009-11-17 15 views
5

Oglądam katalog, dzwoniąc pod numer ReadDirectoryChangesW synchronicznie. Kiedy nowy plik jest dostępny, próbuję uzyskać do niego natychmiastowy dostęp za pomocą CreateFile z GENERIC_READ i FILE_SHARE_READ, ale to daje mi ERROR_SHARING_VIOLATION. Proces, który umieścił plik w obserwowanym katalogu, nie kończy zapisu, gdy spróbuję go odczytać.Oczekiwanie, aż plik będzie dostępny do odczytu za pomocą Win32

Czy istnieje sposób na niezawodne oczekiwanie, aż plik będzie dostępny do odczytu? Mogę umieścić tę metodę w pętli podobnej do poniższej, ale mam nadzieję, że jest lepszy sposób.

while ((hFile = CreateFile (path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) 
{ 
    if (GetLastError() == ERROR_SHARING_VIOLATION) 
     Sleep (500); 
    else 
     break; // some other error occurred 
} 

if (hFile == INVALID_HANDLE_VALUE) 
{ 
    // deal with other error 
    return 0; 
} 

ReadFile (...); 
+0

Zakładam, że to jest C++? Jeśli jest to C#, istnieje obiekt SystemFileWatcher w BCL, którego możesz użyć. –

+0

Win32 == C API, będę retag. – dreamlax

Odpowiedz

2

Brak funkcji trybu użytkownika dla powiadomień o zamkniętym pliku, o których jestem świadomy. Zaproponowana pętla jest prawdopodobnie najlepszym sposobem. Jedyną rzeczą, którą możesz zrobić, to obejrzeć CloseFile w sterowniku filtru ala Process Monitor, ale fuj ...

0

Jeśli wiesz coś na temat tworzenia pliku, może poczekać, aż plik przestanie rosnąć dla X sekund lub poczekaj, aż plik wartownika zostanie usunięty. Lub wyczuj stan programu, który je tworzy.

+0

Niestety nie mam pojęcia, w jaki sposób plik jest generowany lub procesu, który umieszcza go w folderze obserwowanym (może to być dowolny program, lub może to być użytkownik przeciągający i upuszczający plik itp.). – dreamlax

5

Nie sądzę, że istnieje powiadomienie dotyczące rodzaju zdarzenia, którego szukasz, ale jako usprawnienie sugeruję progresywne opóźnienia. W ten sposób uzyskasz szybki czas reakcji na takie rzeczy, jak przeciąganie/upuszczanie i nie będzie hog CPU z ciasną pętlę, jeśli użytkownik utrzymuje plik otwarty przez godzinę w programie Excel.

int delay= 10; 
while ((hFile = CreateFile (path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) 
{ 
    if (GetLastError() == ERROR_SHARING_VIOLATION) { 
     Sleep (delay); 
     if (delay<5120) // max delay approx 5.Sec 
      delay*= 2; 
    } 
    else 
     break; // some other error occurred 
} 
2

Jak powiedział @Matt Davis, niestety nie jest w trybie użytkownika API, ale nie jest rozwiązanie, które w zależności od przypadków użycia (pisałem kopalni poniżej) może robić tylko to, co chcesz.

Co pracował dla mnie w przeszłości był rejestracji dla FILE_NOTIFY_CHANGE_LAST_WRITEzamiastFILE_NOTIFY_CHANGE_FILE_NAME Dzwoniąc ReadDirectoryChangesW:

ZeroMemory(&overlapped, sizeof(OVERLAPPED)); 
overlapped.hEvent = hChangeEvent; 

// ...  
ReadDirectoryChangesW(hSpoolPath, 
         eventBuffer, 
         EVENT_BUF_LENGTH, 
         FALSE, 
         FILE_NOTIFY_CHANGE_LAST_WRITE, // <---- 
         NULL, 
         &overlapped, 
         NULL); 
// ... 
HANDLE events[2]; 

events[0] = hChangeEvent; 
events[1] = hCancelEvent; 

DWORD wRc = WaitForMultipleObjects(2, events, FALSE, DIRECTORY_WATCH_TIMEOUT); 

Ostatni czas zapisu jest aktualizowany jak tylko proces będącym właścicielem zamyka uchwyt po utworzeniu pliku i pisanie do niego.

Mój przypadek użycia był jednym procesem, który odebrał żądania HTTP przez TCP/IP i napisał ciało HTTP do katalogu, w którym inny proces podniósł go zaraz po zakończeniu procesu odbierania (i w konsekwencji zamknięciu zajmij się tym. Serwer http był jedynym procesem, który zapisał do tego katalogu, więc mogłem polegać na schemacie create-write-close.

+0

ReadDirectoryChangesW powiadamia mnie dwa razy, gdy rejestruję się w pliku FILE_NOTIFY_CHANGE_LAST_WRITE, a następnie dodajemy plik do tego folderu. Z jakiego powiadomienia korzystałeś? – Will

Powiązane problemy