Dans C#, SI 2 processus sont en train de lire et d'écrire dans le même fichier, Quelle est la meilleure façon d'éviter les exceptions de verrouillage 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))
{
string fileContents = tr.ReadToEnd();
}
}
et le code d'écriture de fichier suivant:
using (TextWriter tw = new StreamWriter(fileName))
{
tw.Write(fileContents);
tw.Close();
}
La suite détails de l'exception sont vu:
Le processus ne peut pas accéder au fichier "c:tempmyfile.txt', parce que c'est utilisé par un autre processus.
Quelle est la meilleure façon d'éviter cela? Le lecteur nécessité de retenter lors de la réception de l'exception ou est-il une meilleure façon?
noter que le le processus de lecture utilise un FileSystemWatcher pour savoir quand le fichier a été modifié.
notez aussi que, dans ce cas, je suis à la recherche d'alternatives pour partager les chaînes entre les 2 Processus.
8 réponses
vous pouvez ouvrir un fichier pour écrire et seulement verrouiller l'accès en écriture, permettant ainsi à d'autres de lire encore le fichier.
Par exemple,
using (FileStream stream = new FileStream(@"C:\Myfile.txt", FileMode.Open, FileAccess.ReadWrite, FileShare.Read))
{
// Do your writing here.
}
autre accès au fichier ouvre simplement le fichier pour lire et ne pas écrire, et permet le partage readwrite.
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 aurez soit besoin d'utiliser un fichier de verrouillage qui indique que quelqu'un écrit dans le fichier (bien que vous pouvez obtenir une condition de course si pas mis en œuvre avec soin) ou assurez-vous de bloquer le partage d'écriture lors de l'ouverture pour lire et gérer l'exception de sorte que vous pouvez essayer à nouveau jusqu'à ce que vous obtenez l'accès exclusif.
si vous créez un Mutex nommé, vous pouvez définir le mutex dans l'application d'écriture, et faire attendre l'application de lecture jusqu'à ce que le mutex soit libéré.
donc dans le processus de notification qui fonctionne actuellement avec le Gestionnaire de fichiers, il suffit de vérifier pour voir si vous avez besoin d'attendre le mutex, si vous le faites, il va attendre, puis traiter.
Voici un VB exemple D'un Mutex comme ceci que j'ai trouvé, il devrait être assez facile de convertir en C#.
y a-t-il une raison particulière pour ouvrir le fichier avec FileShare.Aucun? Cela empêchera le fichier d'être ouvert par tout autre processus.
FileShare.Écrire ou de partage de fichiers.ReadWrite devrait permettre à l'autre processus (sujet aux permissions) d'ouvrir et d'écrire dans le fichier pendant que vous le lisez, cependant vous aurez à surveiller le changement de fichier en dessous de vous pendant que vous le lisez - simplement buffering le contenu lors de l'ouverture peut aider ici.
Toutes ces réponses, cependant, sont également valables - la meilleure solution dépend exactement 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, puis le verrouiller et gérer l'exception subséquente dans votre code d'écriture; s'il est important de lire et d'écrire à lui en même temps, puis changer la constante FileShare.
obtenez votre processus pour vérifier l'état du fichier s'il est écrit. Vous pouvez le faire par la présence d'un fichier de verrouillage (c'est à dire la présence de cet autre fichier, qui peut être vide, empêche l'écriture pour le fichier principal).
même ceci n'est pas infaillible cependant, car les deux processus peuvent créer le fichier lock en même temps - mais vous pouvez vérifier cela avant de propager l'écriture.
si votre processus rencontre un fichier lock alors obtenir simplement dormir / attendre et essayer de nouveau à un intervalle prédéfini dans l'avenir.
Le lecteur (à l'exclusion de réessayer) devient
using (FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
using (TextReader tr = new StreamReader(fileStream))
{
string fileContents = tr.ReadToEnd();
}
}
L'écrivain (à l'exclusion de réessayer) devient:
FileStream fileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None);
using (TextWriter tw = new StreamWriter(fileStream))
{
tw.Write(fileContents);
tw.Close();
}
écrire dans un fichier temporaire, une fois terminé l'écriture renommer/déplacer le fichier à l'endroit et/ou le nom que le lecteur cherche.
la meilleure chose à faire, est de placer un protocole d'application au-dessus d'un mécanisme de transfert de fichier/propriété. Le mécanisme "lock-file" est un vieux hack UNIX qui existe depuis des siècles. La meilleure chose à faire, c'est de simplement "remettre" le fichier au lecteur. Il y a beaucoup de façons de le faire. 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 a un "lien" pour plus d'informations, pour les images, les scripts, le contenu externe etc. Le serveur vous donne cette page, parce que c'est une vue cohérente de la "ressource" que vous voulez. Votre navigateur va ensuite et obtient le contenu approprié, en fonction de ce que la description de la page (le fichier HTML ou d'autres contenus retournés), puis transfère ce dont il a besoin.
il s'agit du type de mécanisme de "partage" le plus souple à utiliser. Ecrire le fichier, partager le nom, passer au fichier suivant. Le "partageant le nom de" partie, l'atomic main qui permet de s'assurer que les deux parties (le lecteur et l'écrivain) convenez que le contenu est "complète."