En C #, si 2 processus lisent et écrivent dans le même fichier, quel est le meilleur moyen d’éviter les exceptions de locking de processus?

Avec le code de lecture de fichier suivant:

using (FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.None)) { using (TextReader tr = new StreamReader(fileStream)) { ssortingng fileContents = tr.ReadToEnd(); } } 

Et le code d’écriture de fichier suivant:

 using (TextWriter tw = new StreamWriter(fileName)) { tw.Write(fileContents); tw.Close(); } 

Les détails d’exception suivants sont visibles:

Le processus ne peut pas accéder au fichier ‘c: \ temp \ myfile.txt’ car il est utilisé par un autre processus.

Quel est le meilleur moyen d’éviter cela? Le lecteur doit-il réessayer à la réception de l’exception ou existe-t-il un meilleur moyen?

Notez que le processus de lecture utilise FileSystemWatcher pour savoir quand le fichier a été modifié.

Notez également que, dans ce cas, je ne cherche pas d’autres moyens de partager des chaînes entre les deux processus.

Vous pouvez ouvrir un fichier en écriture et verrouiller uniquement l’access en écriture, permettant ainsi à d’autres personnes de lire le fichier.

Par exemple,

 using (FileStream stream = new FileStream(@"C:\Myfile.txt", FileMode.Open, FileAccess.ReadWrite, FileShare.Read)) { // Do your writing here. } 

Un autre access au fichier ouvre simplement le fichier en lecture et en écriture, et permet le partage lecture / écriture.

 using (FileStream stream = new FileStream(@"C:\Myfile.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { // Does reading here. } 

Si vous voulez vous assurer que les lecteurs liront toujours un fichier à jour, vous devrez soit utiliser un fichier de locking indiquant qu’une personne est en train d’écrire dans le fichier (vous pouvez toutefois obtenir une condition de concurrence si elle n’est pas correctement mise en œuvre), ou faire en sorte que Assurez-vous de bloquer le partage en écriture lors de l’ouverture pour lire et gérer l’exception afin de pouvoir réessayer jusqu’à ce que vous obteniez un access exclusif.

Si vous créez un mutex nommé, vous pouvez définir le mutex dans l’application d’écriture et laisser l’application de lecture attendre que le mutex soit libéré.

Ainsi, dans le processus de notification qui fonctionne actuellement avec FileSystemWatcher, vérifiez simplement si vous devez attendre le mutex. Si vous le faites, il attendra, puis traitera.

Voici un exemple de Mutex comme celui-ci que j’ai trouvé dans VB ; il devrait être assez facile de convertir en C #.

Y at-il une raison particulière pour ouvrir le fichier avec FileShare.None? Cela empêchera le fichier d’être ouvert par tout autre processus.

FileShare.Write ou FileShare.ReadWrite devraient permettre à l’autre processus (sous réserve des permissions) de s’ouvrir et d’écrire dans le fichier pendant que vous le lisez, mais vous devrez surveiller le fichier se modifier pendant que vous le lisez – mise en mémoire tampon le contenu à l’ouverture peut aider ici.

Toutes ces réponses, cependant, sont également valables – la meilleure solution dépend de ce que vous essayez de faire avec le fichier: s’il est important de le lire tout en garantissant qu’il ne change pas, verrouillez-le et gérez l’exception suivante. dans votre code d’écriture; s’il est important de lire et d’écrire en même temps, changez la constante FileShare.

Vous pouvez utiliser un object Mutex pour cela.

Demandez à votre processus de vérifier l’état du fichier s’il est en train d’être écrit. Vous pouvez le faire par la présence d’un fichier de locking (c’est-à-dire que la présence de cet autre fichier, qui peut être vide, empêche l’écriture dans le fichier principal).

Même si cela n’est pas sûr, les deux processus peuvent créer le fichier de locking en même temps – mais vous pouvez le vérifier avant de valider l’écriture.

Si votre processus rencontre un fichier de locking, faites-le simplement dormir / attendez et essayez à nouveau à un intervalle prédéfini dans le futur.

Le lecteur et l’écrivain ont tous deux besoin de mécanismes de nouvelle tentative. FileShare doit également être défini sur FileShare.read pour les lecteurs et sur FileShare.none pour le rédacteur. Cela devrait garantir que les lecteurs ne lisent pas le fichier alors que l’écriture est en cours.

Le lecteur (sauf nouvelle tentative) devient

 using (FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { using (TextReader tr = new StreamReader(fileStream)) { ssortingng fileContents = tr.ReadToEnd(); } } 

L’écrivain (sauf nouvelle tentative) devient:

 FileStream fileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None); using (TextWriter tw = new StreamWriter(fileStream)) { tw.Write(fileContents); tw.Close(); } 

Écrivez dans un fichier temporaire. Une fois l’écriture terminée, renommez / déplacez le fichier à l’emplacement et / ou au nom recherché par le lecteur.

La meilleure chose à faire est de placer un protocole d’application au-dessus d’un mécanisme de transfert de fichier / transfert de propriété. Le mécanisme de “fichier de locking” est un vieux hack UNIX qui existe depuis des lustres. La meilleure chose à faire est de simplement “remettre” le fichier au lecteur. Il y a plusieurs manières de faire ça. Vous pouvez créer le fichier avec un nom de fichier aléatoire, puis “donner” ce nom au lecteur. Cela permettrait à l’auteur d’écrire de manière asynchrone un autre fichier. Pensez au fonctionnement de la “page Web”. Une page Web contient un “lien” vers plus d’informations, pour des images, des scripts, du contenu externe, etc. Le serveur vous transmet cette page, car il s’agit d’une vue cohérente de la “ressource” souhaitée. Votre navigateur récupère ensuite le contenu approprié, en fonction de la description de la page (le fichier HTML ou tout autre contenu renvoyé), puis transfère ce dont il a besoin.

C’est le type de mécanisme de “partage” le plus résistant à utiliser. Écrivez le fichier, partagez le nom, passez au fichier suivant. La partie “partage du nom” est le transfert atomique qui permet de s’assurer que les deux parties (le lecteur et l’auteur) s’accordent pour dire que le contenu est “complet”.