2009-11-17 7 views
5

Je regarde un répertoire en appelant le ReadDirectoryChangesW de manière synchrone. Quand un nouveau fichier est disponible, j'essaie d'y accéder immédiatement avec CreateFile avec GENERIC_READ et FILE_SHARE_READ, mais cela me donne ERROR_SHARING_VIOLATION. Le processus qui place le fichier dans le répertoire surveillé ne termine pas l'écriture au moment où j'essaie de le lire.En attente de lecture d'un fichier avec Win32

Existe-t-il un moyen d'attendre de manière fiable que le fichier soit disponible en lecture? Je peux mettre la méthode en boucle comme celle ci-dessous, mais j'espère qu'il y aura un meilleur moyen.

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

Je suppose que c'est C++? S'il s'agit de C#, il existe un objet SystemFileWatcher dans la BCL que vous pouvez utiliser. –

+0

Win32 == C API, je vais retag. – dreamlax

Répondre

2

Il n'y a pas d'API en mode utilisateur pour les notifications sur un fichier fermé dont je suis au courant. La boucle que vous avez proposée est probablement la meilleure. La seule autre chose que vous pourriez faire serait de regarder CloseFile dans un pilote de filtre dans un moniteur de processus, mais beurk ...

0

Si vous savez quelque chose sur la façon dont le fichier est créé, attendez peut-être que le fichier cesse de croître pour X secondes, ou attendez qu'un fichier Sentinel soit supprimé. Ou sentir l'état du programme qui les crée.

+0

Malheureusement, je n'ai aucune idée de la façon dont le fichier est généré ou du processus qui le place dans le dossier surveillé (il peut s'agir de n'importe quel programme, ou de l'utilisateur qui fait glisser et déposer un fichier, etc.). – dreamlax

5

Je ne pense pas qu'il existe une notification pour le type d'événement que vous recherchez, mais en guise d'amélioration, je suggérerais des retards progressifs. De cette façon, vous obtiendrez des temps de réponse rapides pour des choses comme un glisser/déposer et ne monopoliserez pas le CPU avec une boucle serrée si l'utilisateur garde le fichier ouvert pendant une heure dans 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

Comme Davis @ Matt dit, il n'y a malheureusement pas d'API en mode utilisateur, mais il existe une solution qui selon votre cas d'utilisation (je le mien ai écrit ci-dessous) peut faire exactement ce que vous voulez.

Ce qui a fonctionné pour moi dans le passé enregistrait pour FILE_NOTIFY_CHANGE_LAST_WRITEau lieu deFILE_NOTIFY_CHANGE_FILE_NAME lorsque vous appelez 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); 

La dernière fois d'écriture est mise à jour dès que le processus possédante ferme la poignée après la création du fichier et en écrivant. Mon cas d'utilisation était un processus qui recevait des requêtes HTTP via TCP/IP et écrivait le corps HTTP dans un répertoire, où un autre processus le récupérait dès que le processus de réception avait fini d'écrire (et par conséquent fermait le gérer). Le serveur http était le seul processus qui écrivait dans ce répertoire, donc je pouvais compter sur le pattern create-write-close.

+0

ReadDirectoryChangesW me notifie deux fois lorsque je m'inscris pour FILE_NOTIFY_CHANGE_LAST_WRITE, puis ajoute un fichier dans le dossier. Quelle notification avez-vous utilisée? – Will