9
votes

En attente jusqu'à ce qu'un fichier soit disponible pour lire avec Win32

Je regarde un répertoire en appelant 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.

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>

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 (...);


1 commentaires

Je suppose que c'est c ++? Si c'est C #, il existe un objet SystemFileWatcher dans la BCL que vous pouvez utiliser.


4 Réponses :


2
votes

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 dans un moniteur de processus de pilote de filtre, mais yuck ...


0 commentaires

0
votes

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.


1 commentaires

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.).



8
votes

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
}


0 commentaires

2
votes

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> au lieu de strong> 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);


1 commentaires

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?