Je regarde un répertoire en appelant Y a-t-il un moyen d'attendre de manière fiable jusqu'à ce que le fichier soit disponible pour la lecture? Je peux mettre la méthode dans une boucle comme celle ci-dessous, mais j'espère qu'il y a une meilleure façon. P> readdirectorychangangesw code> de manière synchrone. Lorsqu'un nouveau fichier est disponible, j'essaie d'y accéder immédiatement avec
Createefile code> avec
generic_read code> et
file_share_read code>, mais cela me donne
error_sharing_violation . Le processus qui met le fichier dans le répertoire observé ne finit pas l'écriture au moment où j'essaie de le lire.
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 (...);
4 Réponses :
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 probablement la meilleure façon. La seule autre chose que vous pourriez faire serait de regarder pour fermerfile code> dans un moniteur de processus de pilote de filtre, mais yuck ... p>
Si vous savez quelque chose sur la manière dont le fichier est créé, attendez peut-être que le fichier cesse de croître pendant x secondes ou d'attendre qu'un fichier sentinel soit supprimé. Ou sentir l'état du programme qui les crée. P>
Malheureusement, je n'ai aucune idée de la manière dont le fichier est généré ou que le processus qui la met dans le dossier surveillé (il pourrait s'agir d'un programme, ou peut être l'utilisateur en train de faire glisser et de déposer un fichier, etc.).
Je ne pense pas qu'il y ait une notification pour le type d'événement que vous recherchez, mais comme une amélioration, je suggérerais des retards progressifs. De cette façon, vous obtiendrez des temps de réponse rapides pour des trucs comme une glisser / goutte et ne ferez pas la CPU avec une boucle serrée si l'utilisateur conserve 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 }
Comme @matt Davis a dit, il n'y a malheureusement pas d'API en mode utilisateur, mais il existe une solution de contournement qui dépendant de votre cas d'utilisation (j'ai écrit le mien ci-dessous) peut faire exactement ce que vous voulez.
Qu'est-ce qui a fonctionné pour Moi dans le passé était d'enregistrer pour file_notify_change_last_write code>
file_notify_change_file_name code> Lorsque vous appelez
listredirectorychanganesw p>
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);
ReadDirectoryChangesw vous avertit deux fois lorsque je vous inscrivez à fichier_notify_change_last_write, puis ajoutez un fichier au dossier. Quelle notification avez-vous utilisée?
Je suppose que c'est c ++? Si c'est C #, il existe un objet SystemFileWatcher dans la BCL que vous pouvez utiliser.