Comment lire un fichier texte sans le verrouiller?

94

J'ai un service Windows écrit son journal dans un fichier texte dans un format simple.

Maintenant, je vais créer une petite application pour lire le journal du service et afficher à la fois le journal existant et celui ajouté en vue en direct.

Le problème est que le service verrouille le fichier texte pour ajouter les nouvelles lignes et en même temps l'application de visualisation verrouille le fichier pour la lecture.

Le code de service:

void WriteInLog(string logFilePath, data)
{
    File.AppendAllText(logFilePath, 
                       string.Format("{0} : {1}\r\n", DateTime.Now, data));
}

Le code du spectateur:

int index = 0;
private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                using (StreamReader sr = new StreamReader(logFilePath))
                {
                    while (sr.Peek() >= 0)  // reading the old data
                    {
                        AddLineToGrid(sr.ReadLine());
                        index++;
                    }
                    sr.Close();
                }

                timer1.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }


private void timer1_Tick(object sender, EventArgs e)
        {
            using (StreamReader sr = new StreamReader(logFilePath))
            {
                // skipping the old data, it has read in the Form1_Load event handler
                for (int i = 0; i < index ; i++) 
                    sr.ReadLine();

                while (sr.Peek() >= 0) // reading the live data if exists
                {
                    string str = sr.ReadLine();
                    if (str != null)
                    {
                        AddLineToGrid(str);
                        index++;
                    }
                }
                sr.Close();
            }
        }

Y a-t-il un problème dans mon code en lecture et en écriture?

Comment résoudre le problème?

Homam
la source

Réponses:

120

Vous devez vous assurer que le service et le lecteur ouvrent le fichier journal de manière non exclusive. Essaye ça:

Pour le service - l'écrivain dans votre exemple - utilisez une FileStreaminstance créée comme suit:

var outStream = new FileStream(logfileName, FileMode.Open, 
                               FileAccess.Write, FileShare.ReadWrite);

Pour le lecteur, utilisez le même mais modifiez l'accès aux fichiers:

var inStream = new FileStream(logfileName, FileMode.Open, 
                              FileAccess.Read, FileShare.ReadWrite);

De plus, depuis FileStreamimplements, IDisposableassurez-vous que dans les deux cas, vous envisagez d'utiliser une usinginstruction, par exemple pour l'écrivain:

using(var outStream = ...)
{
   // using outStream here
   ...
}

Bonne chance!

Manfred
la source
Il y a aussi la version ReadLines () sur stackoverflow.com/questions/5338450/…
Colin
Parfait - j'avais pensé que File.Open () avec FileAccess.Read était suffisant, mais ce n'est pas le cas. Ceci est, cependant. :)
neminem
Sur l'écrivain, FileShare.Read ne suffirait-il pas puisqu'il n'y a qu'un seul écrivain?
crokusek
2
Aussi, il convient de noter que FileStreamimplémenteIDisposable
semainesdev
28

Configuration explicite du mode de partage lors de la lecture du fichier texte.

using (FileStream fs = new FileStream(logFilePath, 
                                      FileMode.Open, 
                                      FileAccess.Read,    
                                      FileShare.ReadWrite))
{
    using (StreamReader sr = new StreamReader(fs))
    {
        while (sr.Peek() >= 0) // reading the old data
        {
           AddLineToGrid(sr.ReadLine());
           index++;
        }
    }
}
têtes5150
la source
2
il n'est pas nécessaire de fermer explicitement le flux, car StreamReader.Dispose le ferme automatiquement.
nothrow
2
Je crois que le partage de fichiers doit être défini sur LES DEUX flux de lecture et d'écriture, et pas seulement en lecture.
LEO
StreamReader.Dispose supprime également FileStream si je ne me trompe pas. Ici, il est disposé deux fois.
Eregrith
12
new StreamReader(File.Open(logFilePath, 
                           FileMode.Open, 
                           FileAccess.Read, 
                           FileShare.ReadWrite))

-> cela ne verrouille pas le fichier.

pas jeter
la source
1
Semble fonctionner lors de la lecture des données. Lors de l'écriture, l'erreur de fichier verrouillé apparaît.
webzy
8

Le problème est que lorsque vous écrivez dans le journal, vous verrouillez exclusivement le fichier afin que votre StreamReader ne soit pas autorisé à l'ouvrir du tout.

Vous devez essayer d'ouvrir le fichier en mode lecture seule .

using (FileStream fs = new FileStream("myLogFile.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    using (StreamReader sr = new StreamReader(fs))
    {
        while (!fs.EndOfStream)
        {
            string line = fs.ReadLine();
            // Your code here
        }
    }
}
James
la source
Comme je le sais maintenant, File.ReadAllText()échoue avec le mode lecture seule.
bohdan_trotsenko
@modosansreves ouais, j'ai supprimé cette partie de la réponse car la documentation indique qu'elle lancera un message UnauthorizedAccessExceptionsi le fichier est en lecture seule - doit avoir manqué cela au moment de la réponse!
James
5

Je me souviens avoir fait la même chose il y a quelques années. Après quelques requêtes Google, j'ai trouvé ceci:

    FileStream fs = new FileStream(@”c:\test.txt”, 
                                   FileMode.Open, 
                                   FileAccess.Read,        
                                   FileShare.ReadWrite);

c'est-à-dire utiliser l'attribut FileShare.ReadWrite sur FileStream ().

(trouvé sur le blog de Balaji Ramesh )

dotmartin
la source
1

Avez-vous essayé de copier le fichier, puis de le lire?

Mettez simplement à jour la copie chaque fois que de gros changements sont effectués.

Tom Gullen
la source
2
J'ai essayé cela et ce n'est pas la meilleure solution. La copie du fichier prend trop de temps, car un fichier de 4 Mo prend environ 20 secondes.
Seichi
-1

Cette méthode vous aidera à lire plus rapidement un fichier texte et sans le verrouiller.

private string ReadFileAndFetchStringInSingleLine(string file)
    {
        StringBuilder sb;
        try
        {
            sb = new StringBuilder();
            using (FileStream fs = File.Open(file, FileMode.Open))
            {
                using (BufferedStream bs = new BufferedStream(fs))
                {
                    using (StreamReader sr = new StreamReader(bs))
                    {
                        string str;
                        while ((str = sr.ReadLine()) != null)
                        {
                            sb.Append(str);
                        }
                    }
                }
            }
            return sb.ToString();
        }
        catch (Exception ex)
        {
            return "";
        }
    }

J'espère que cette méthode vous aidera.

Amit Kumawat
la source
1
Pour autant que je sache, cette méthode lit un fichier entier dans une chaîne et avale les exceptions en cours de route. Je ne vois pas comment cela est censé aider à verrouiller les fichiers.
locale par défaut