3 votes

Comment vérifier s'il y a suffisamment d'espace avant WriteFile en c dans Windows?

  hPipe = CreateNamedPipe( 
     lpszPipename,             // nom du pipe 
     PIPE_ACCESS_DUPLEX,       // accès lecture/écriture 
     PIPE_TYPE_MESSAGE |       // type de pipe message 
     PIPE_READMODE_MESSAGE |   // mode lecture de message 
     PIPE_WAIT,                // mode bloquant 
     PIPE_UNLIMITED_INSTANCES, // instances max. 
     100,                  // taille du tampon de sortie 
     100,                  // taille du tampon d'entrée 
     0,                        // délai d'attente client 
     NULL);                    // attribut de sécurité par défaut 

  DWORD totalBytesAvailable; 
  PeekNamedPipe( 
    hPipe ,                // __in       HANDLE hNamedPipe, 
    NULL,                  // __out_opt  LPVOID lpBuffer, 
    0,                     // __in       DWORD nBufferSize, 
    NULL,                  // __out_opt  LPDWORD lpBytesRead, 
    &totalBytesAvailable,  // __out_opt  LPDWORD lpTotalBytesAvail, 
    NULL                   // __out_opt  LPDWORD lpBytesLeftThisMessage 
  ); 
    if(totalBytesAvailable permet)
    WriteFile( tmp_pipe, pBuffer, BufferLen, &dwWritten, NULL );

Comme vous pouvez le voir, j'ai utilisé PeekNamedPipe pour obtenir l'espace disponible, mais il s'avère que totalBytesAvailable est toujours 0, comment faire correctement ?

4voto

tudor Points 66

À mon avis, cette approche de vérifier l'espace libre avant de faire l'écriture réelle est déficiente.

Il se pourrait que, lorsque l'écriture réelle est exécutée, un autre processus s'exécutant en parallèle remplisse les derniers bits d'espace disque libre, entraînant ainsi l'échec de votre WriteFile.

Je me fierais uniquement à ce que WriteFile retourne.

2voto

Foredecker Points 5784

Les valeurs retournées dans le paramètre lpTotalBytesAvail sont le nombre d'octets qui peuvent être lus à partir d'un tube, pas écrits dans le tube. Cela vous donne l'information nécessaire pour allouer un tampon pour lire des données à partir d'un tube.

La bonne approche pour gérer les erreurs lors de l'écriture dans un tube - ou tout autre handle NT Kernel - est simplement d'exécuter l'appel à WriteFile() et de gérer les erreurs retournées.

Le modèle de vérification puis écriture n'est pas efficace et entraînera des bugs qui * Ne se produisent jamais dans vos tests * Se produisent parfois sur le terrain * ... et sont donc très difficiles à diagnostiquer et à déboguer * surtout, de tels bugs agaceront vos utilisateurs.

La raison en est que l'état de la destination peut changer entre la vérification et l'écriture réelle. Cela signifie que votre code qui appelle WriteFile() doit de toute façon vérifier les erreurs. Cela signifie que vérifier une pré-condition avant d'appeler WriteFile() est simplement du code supplémentaire qui ne fournit aucune valeur.

La raison pour laquelle ce modèle n'est pas efficace est que Windows (et tous les autres systèmes d'exploitation - ce n'est pas juste une chose de Windows) - ne peut pas traiter la "vérification" et l'écriture" comme des opérations atomiques. Le système d'exploitation sous-jacent est entièrement asynchrone et beaucoup de choses peuvent arriver entre les appels.

Par conséquent, votre code sera plus simple et plus fiable si vous appelez simplement WriteFile() et que vous faites un bon travail de gestion des erreurs.

-Foredecker

1voto

Paul Dixon Points 122033

Vous ne pouvez pas déterminer l'espace libre de la manière dont vous le faites.

Alors que cette question concerne les tuyaux, il est possible que des personnes la trouvent en cherchant des informations générales sur la découverte de l'espace disque disponible, et si le tuyau est finalement un fichier, cela pourrait toujours être utile :

L'article de la base de connaissances "Comprendre et Utiliser GetDiskFreeSpace et GetDiskFreeSpaceEx" donne des informations sur les API Win32 pertinentes pour déterminer l'espace disque libre, ou allez directement à la documentation de l'API ici :

1voto

TonyK Points 8604

Configurez PIPE_NOWAIT au lieu de PIPE_WAIT. Ensuite, WriteFile renverra immédiatement s'il n'y a pas assez de place dans le tube.
Et 100 semble assez petit pour les tailles de mémoire tampon E/S! À quoi sert votre tube?

1voto

Ian Goldby Points 1535

Les commentaires concernant la fragilité de la vérification puis l'écriture sont corrects.

La suggestion de PIPE_NOWAIT n'est pas recommandée par Microsoft.

Utilisez des E/S superposées. Ensuite, WriteFile() retournera toujours immédiatement, et renverra FALSE avec ERROR_IO_PENDING si les données n'ont pas été immédiatement écrites dans le tuyau. Dans ce cas, appelez CancelIo() pour annuler la tentative de WriteFile(). Gardez à l’esprit qu'après avoir appelé CancelIo(), vous devez ensuite appeler GetOverlappedResult() car l'E/S superposée de WriteFile() doit encore être complétée - même si elle va échouer et si vous libérez la structure OVERLAPPED avant qu'elle ne se fasse, vous risquez une corruption de la pile.

En passant, vous devriez accepter une réponse sur cette question. Cela fait plus d'un an que vous l'avez posée!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X