Entwickler-Ecke
WinForms - Datei-Inhalte live anzeigen (und Inhalte aktuell halten)
rittergig - Di 23.08.11 14:25
Titel: Datei-Inhalte live anzeigen (und Inhalte aktuell halten)
Ich möchte den Inhalt einer Datei in einer Textbox in Echtzeit anzeigen.
Wenn die Anwendung gestartet ist, soll sie immer den aktuellen Inhalt einer Datei anzeigen.
Also wenn ich die Datei mit einem Text-Editor öffne und was hinzufüge und dann wieder abspeicher soll das auch im Programm angezeigt werden.
Wie kann ich das realisieren außer ständig zu pollen.
Hat der StreamReader irgendein Event für aktualisierung oder kann ich an ein Textfeldcontrol direkt den Stream als Datasource übergeben?
Grüße, Peter
lothi - Di 23.08.11 14:35
Hallo
Ja, dafür gibs die FileSystemWatcher - Klasse
Gruss Lothi
rittergig - Di 23.08.11 21:41
lothi hat folgendes geschrieben : |
| Ja, dafür gibs die FileSystemWatcher - Klasse |
Danke. Damit gehts.
Allerdings habe ich noch das Problem, dass das Changed-Ereignis beim Speichern einer Datei 2 mal (oder noch öfter) ausgelöst wird.
Ich habe die Eigenschaft NotifyFilter = NotifyFilters.Attributes festgelegt.
Dennoch wird der Event-Handler "_FileSystemWatcher_Changed" 2x aufgerufen.
Leider kann ich auch nicht den 2. Aufruf anhand des FileSystemEventArgs filtern, da diese Argumente völlig identisch sind.
Wie kann ich das Problem beheben?
Grüße Peter
lothi - Do 25.08.11 12:28
Hallo
Hmm so vom Ufer aus kann ich auch nicht sagen wieso. Setz mal ein Breakpoint und fahre mit dem Debugger durch.
Vielleicht siehst du wo und wann das Event gefeurt wird.
Gruss Lothi
rittergig - Do 25.08.11 19:51
Die Events werden nahezu parallel gefeuert. Das merke ich daran, dass ich, sobald sich eine Datei ändert, ich die Datei anzeigen möchte.
Oft erhalte ich aber eine Exception, weil bereits ein StreamReader die Datei geöffnet hat.
Hier mal mein Quellcode:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85:
| public partial class Form1 : Form { #region Fiels private FileInfo _OpenedFile; private FileSystemWatcher _FileSystemWatcher; #endregion
#region Constructors public Form1() { InitializeComponent(); } #endregion
#region Private Methods private void ShowFile(string filePath) { InvokeIfRequired(this.textBoxFileContent, (MethodInvoker)delegate() { for (int i = 0; i < 5; i++) { try { using (StreamReader sr = new StreamReader(filePath)) { this.textBoxFileContent.Text = sr.ReadToEnd(); sr.Close(); } break; } catch (IOException) { System.Threading.Thread.Sleep(50); } } }); }
private void InvokeIfRequired(Control target, Delegate methodToInvoke) { if (target.InvokeRequired) { target.Invoke(methodToInvoke); } else { methodToInvoke.DynamicInvoke(); } } #endregion
private void buttonOpenFile_Click(object sender, EventArgs e) { string filePath = textBoxFilePath.Text;
if (File.Exists(filePath) == true) { this._OpenedFile = new FileInfo(filePath);
this._FileSystemWatcher = new FileSystemWatcher() { Path = this._OpenedFile.DirectoryName, Filter = this._OpenedFile.Name, NotifyFilter = NotifyFilters.Attributes, IncludeSubdirectories = false, EnableRaisingEvents = true, }; this._FileSystemWatcher.Changed += new FileSystemEventHandler(this._FileSystemWatcher_Changed);
this.ShowFile(this._OpenedFile.FullName); } }
void _FileSystemWatcher_Changed(object sender, FileSystemEventArgs e) { this.ShowFile(this._OpenedFile.FullName); } } |
Wenn ich auf den Button klicke, wird die Datei angezeigt.
Bei Änderung soll die Anzeige aktualisiert werden.
Problem ist nur, dass das Event 2x gefeuert wird.
Mit
NotifyFilter = NotifyFilters.Size
wird das Event nur 1x gefeuert.
Aber ich bekomme dann nicht mit, wenn sich die Datei ändert, jedoch die Größe konstant bleibt.
Grüße Peter
Trashkid2000 - Do 25.08.11 21:53
Hallo Peter,
also nachdem ich das auf stackoverflow (
http://stackoverflow.com/questions/1764809/filesystemwatcher-changed-event-is-raised-twice) gelesen habe ist es wohl das beste, wenn man sich im Prozess einfach das letzte Änderungsdatum merkt. Und dann im Event mit diesem vergleicht. Das würde dann so aussehen:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
| private void button1_Click(object sender, EventArgs e) { string filePath = @"c:\temp\testfile.txt"; if (File.Exists(filePath)) { DateTime lastFileChangedTime = File.GetLastWriteTime(filePath); FileSystemWatcher watcher = new FileSystemWatcher() { Path = Path.GetDirectoryName(filePath), Filter = Path.GetFileName(filePath), NotifyFilter = NotifyFilters.Attributes, IncludeSubdirectories = false, EnableRaisingEvents = true, }; watcher.Changed += (x, y) => { if (File.GetLastWriteTime(filePath) != lastFileChangedTime) { lastFileChangedTime = File.GetLastWriteTime(filePath); } }; } } |
LG,
rittergig - Fr 26.08.11 09:02
Danke. Aber schade, dass es nicht out-of-the-box richtig funktioniert.
Das Problem bei dieser Lösung ist, dass die Befehle nicht in einer Transaktion gekapselt sind. Es könnte ja sein, dass bevor die LastWrite-Zeit auslesen wird, die Datei bereits erneut geändert wurde. Evtl. müsste man sogar mit Semaphoren arbeiten.
Aber erst einmal funktioniert der Hack :)
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!