c # lecture continue du fichier

Je veux lire le fichier continuellement comme GNU tail avec “-f” param. J’en ai besoin pour lire en direct le fichier journal. Quelle est la bonne façon de le faire?

Vous voulez ouvrir un FileStream en mode binary. Périodiquement, cherchez jusqu’à la fin du fichier moins 1024 octets (ou quoi que ce soit), puis lisez-le jusqu’à la fin et affichez-le. C’est comme ça que la tail -f fonctionne.

Réponses à vos questions:

Binaire, car il est difficile d’accéder au fichier de manière aléatoire si vous le lisez sous forme de texte. Vous devez faire la conversion binary en texte vous-même, mais ce n’est pas difficile. (Voir ci-dessous)

1024 octets parce que c’est un bon nombre commode et devrait pouvoir traiter 10 ou 15 lignes de texte. Habituellement.

Voici un exemple d’ouverture du fichier, de lecture des 1024 derniers octets et de conversion en texte:

 static void ReadTail(ssortingng filename) { using (FileStream fs = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { // Seek 1024 bytes from the end of the file fs.Seek(-1024, SeekOrigin.End); // read 1024 bytes byte[] bytes = new byte[1024]; fs.Read(bytes, 0, 1024); // Convert bytes to ssortingng ssortingng s = Encoding.Default.GetSsortingng(bytes); // or ssortingng s = Encoding.UTF8.GetSsortingng(bytes); // and output to console Console.WriteLine(s); } } 

Notez que vous devez ouvrir avec FileShare.ReadWrite , car vous essayez de lire un fichier en cours d’écriture par un autre processus.

Notez également que j’ai utilisé Encoding.Default , qui en anglais / US et pour la plupart des langues d’Europe occidentale sera un encodage de caractères à 8 bits. Si le fichier est écrit dans un autre codage (comme UTF-8 ou un autre codage Unicode), il est possible que les octets ne soient pas convertis correctement en caractères. Vous devrez gérer cela en déterminant l’encodage si vous pensez que cela posera problème. La stack de recherche déborde d’informations sur la détermination du codage du texte d’un fichier.

Si vous souhaitez effectuer cela périodiquement (toutes les 15 secondes, par exemple), vous pouvez configurer une timer qui appelle la méthode ReadTail aussi souvent que vous le souhaitez. Vous pouvez optimiser un peu les choses en ouvrant le fichier une seule fois au début du programme. C’est à toi de voir.

Approche plus naturelle de l’utilisation de FileSystemWatcher :

  var wh = new AutoResetEvent(false); var fsw = new FileSystemWatcher("."); fsw.Filter = "file-to-read"; fsw.EnableRaisingEvents = true; fsw.Changed += (s,e) => wh.Set(); var fs = new FileStream("file-to-read", FileMode.Open, FileAccess.Read, FileShare.ReadWrite); using (var sr = new StreamReader(fs)) { var s = ""; while (true) { s = sr.ReadLine(); if (s != null) Console.WriteLine(s); else wh.WaitOne(1000); } } wh.Close(); 

Ici, le cycle de lecture principal cesse d’attendre les données entrantes et FileSystemWatcher est utilisé uniquement pour réveiller le cycle de lecture principal.

Pour surveiller en permanence la queue du fichier, il vous suffit de vous rappeler la longueur du fichier avant.

 public static void MonitorTailOfFile(ssortingng filePath) { var initialFileSize = new FileInfo(filePath).Length; var lastReadLength = initialFileSize - 1024; if (lastReadLength < 0) lastReadLength = 0; while (true) { try { var fileSize = new FileInfo(filePath).Length; if (fileSize > lastReadLength) { using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { fs.Seek(lastReadLength, SeekOrigin.Begin); var buffer = new byte[1024]; while (true) { var bytesRead = fs.Read(buffer, 0, buffer.Length); lastReadLength += bytesRead; if (bytesRead == 0) break; var text = ASCIIEncoding.ASCII.GetSsortingng(buffer, 0, bytesRead); Console.Write(text); } } } } catch { } Thread.Sleep(1000); } } 

J’ai dû utiliser ASCIIEncoding, car ce code n’est pas assez intelligent pour prendre en charge les longueurs de caractères variables de UTF8 sur les limites de la mémoire tampon.

Remarque: vous pouvez modifier la partie Thread.Sleep en différents timings et vous pouvez également la lier avec un gestionnaire de fichiers et un modèle de blocage – Monitor.Enter / Wait / Pulse. Pour moi, le minuteur est suffisant et au plus, il ne vérifie la longueur du fichier que toutes les secondes, si le fichier n’a pas changé.

Vous pouvez utiliser la classe FileSystemWatcher qui peut envoyer des notifications pour différents événements se produisant sur le système de fichiers, comme le fichier modifié.

C’est ma solution

  static IEnumerable TailFrom(ssortingng file) { using (var reader = File.OpenText(file)) { while (true) { ssortingng line = reader.ReadLine(); if (reader.BaseStream.Length < reader.BaseStream.Position) reader.BaseStream.Seek(0, SeekOrigin.Begin); if (line != null) yield return line; else Thread.Sleep(500); } } } 

alors, dans votre code, vous pouvez faire

  foreach (ssortingng line in TailFrom(file)) { Console.WriteLine($"line read= {line}"); } 
 private void button1_Click(object sender, EventArgs e) { if (folderBrowserDialog.ShowDialog() == DialogResult.OK) { path = folderBrowserDialog.SelectedPath; fileSystemWatcher.Path = path; ssortingng[] str = Directory.GetFiles(path); ssortingng line; fs = new FileStream(str[0], FileMode.Open, FileAccess.Read, FileShare.ReadWrite); tr = new StreamReader(fs); while ((line = tr.ReadLine()) != null) { listBox.Items.Add(line); } } } private void fileSystemWatcher_Changed(object sender, FileSystemEventArgs e) { ssortingng line; line = tr.ReadLine(); listBox.Items.Add(line); } 

Si vous cherchez simplement un outil pour le faire, consultez la version gratuite de Bare tail