hi forum,
ich habe eine datei, welche stetig beschrieben wird (logfile).
nun möchte ich diese datei mittels filestream auslesen, was aber nicht geht.
mein programm bleibt aber einfach stehen und wartet.
also habe ich probiert, die datei zuerst mittels File.Copy zu kopieren
und dann mit dieser kopie zu arbeiten. die kopie wird aber nicht angelegt.
was kann ich tun?
mfg nullpunkt
Hallo Nullpunkt,
wenn der FileShare-Modus von Writer- und Reader-Programm zueinander passen, sollte es kein Problem sein, die Datei zu lesen.
herbivore
hi herbivore,
ups, das habe ich übersehen. danke, nun klappts wie am schnürchen.
mfg
nulllpunkt
hi,
ich muss dieses thema betreffend leider nochmals nachhaken.
FileStream Fs = new FileStream("MyLogfile.txt", FileMode.Open, FileAccess.Read, FileShare.Write);
Byte[] Buffer = new Byte[1024];
StringBuilder Sb = new StringBuilder();
while (Fs.Read(Buffer, 0, Buffer.Length) > 0)
{
Sb.Append(Encoding.UTF8.GetString(Buffer, 0, Buffer.Length));
}
String FileContent = Sb.ToString();
String[] Lines = FileContent.Split(new String[] { Environment.NewLine }, StringSplitOptions.None);
nun, auf der letzten zeile erhalte ich nun eine OutOfMemoryException.
das ursprüngliche file kann eine grösse bis zu 200MB haben. gibt es eine
bessere art einzulesen?
mfg
nullpunkt
Hi Nullpunkt,
File.ReadAllLines(string path, Encoding encoding)
oder
StreamReader.ReadLine()
könnten interessant sein.
Spo
Hallo Nullpunkt,
wieso schreibst du den gesamten Inhalt der Datei in einen StringBuilder?
Schreibe ihn doch mithilfe eines zweiten _FileStream_s direkt in die neue Datei. Ansonsten gehst du einen Umweg über den Arbeitsspeicher.
BTW: Vergiss nicht, die beiden _FileStream_s wieder zu Closen bzw. zu Disposen bzw. einen using
- Block zu verwenden.
//EDIT:
File.ReadAllLines(string path, Encoding encoding) oder StreamReader.ReadLine()
Wobei da auch wieder alles in den RAM geladen wird. Bei einer Dateigröße von 200MB freut sich der User da sicherlich nicht sonderlich drüber.
hi zusammen,
bei File.ReadAllLines kann ich das zwingende 'FileShare' nicht mitgeben.
und da auf die datei stetig zugegriefen wird, komme ich da nicht drum rum.
und da ich die datei danach zeilenweise verarbeiten muss,
komme muss ich sie ja irgendwie zur verfügung im speicher haben.
oder sehe ich da was falsch?
mfg
nullpunkt
Hi Nullpunkt,
du könntest die Datei zeilenweise mit Hilfe des StreamReaders einlesen und die jeweils eingelesene Zeile direkt verarbeiten. So bleibt der Speicherverbraucht niedrig.
Spo
Hallo!
Bzgl. der OutOfMemoryException: Die kommt daher, dass die Daten insgesamt 3x im Speicher liegen: Einmal als StringBuilder, einmal als String und einmal als String-Array.
Du solltest also lieber eine generische Liste nehmen, und diese mittels StramReader.ReadLine().Split... füllen.
Edit: Mist, zu spät
Nobody is perfect. I'm sad, i'm not nobody 🙁
hi zusammen,
nun, obwohl ich auf der aktuellen station 4gb ram habe, erhalte ich
sogar bei folgendem code die OutOfMemoryException:
FileStream Fs = new FileStream(LogfileFileDialog.FileName, FileMode.Open, FileAccess.Read, FileShare.Write);
StreamReader Sr = new StreamReader(Fs);
String[] Lines = Sr.ReadToEnd().Split(new String[] { Environment.NewLine }, StringSplitOptions.None);
ich sehe jetzt grad auch, dass ich noch viel freien speicher habe. denke also,
es liegt nicht am arbeitsspeicher, sondern an etwas anderem.
@tom-essen:
wäre hier eine generische liste einem string vorzuziehen, sicher?
mfg nullpunkt
Auch wenn es nicht am Arbeitsspeicher liegen sollte, was ich aber immer noch denke, ist es eine ziemliche Verschwendung, derartigen Code zu schreiben.
User mit weniger RAM ständen da nämlich unnötigerweise "ziemlich blöd da".
Probiere doch die genannten Tipps einmal aus - vielleicht löst sich das Problem dadurch.
hi,
schreiben den die generischen typen ihre ressourcen nicht in den arbeitsspeicher?
ich habs jetzt so gelöst:
FileStream Fs = new FileStream(LogfileFileDialog.FileName, FileMode.Open, FileAccess.Read, FileShare.Write);
StreamReader Sr = new StreamReader(Fs);
List<String> Lines = new List<String>();
while (!Sr.EndOfStream)
{
Lines.Add(Sr.ReadLine());
}
und es funktioniert tatsächlich - sauber und schnell.
danke vielmals für eure hilfe!
mfg
nullpunkt
Nochmal zur Klarheit:
Du hast eine Logdatei, die du nur erweitern möchtest. Ihr vorheriger Inhalt ist dir programmtechnisch gesehen aber egal.
Um die Logdatei zu erweitern, soll jedesmal eine Kopie angelegt werden, die dann erweitert wird.
Irgendwie habe ich das Gefühl, etwas falsch verstanden zu haben.
hi,
nein, ich habe eine bereits aus einem anderen programm bestehenden logdatei,
in welche mehrmals pro sekunde geschrieben wird. (nicht von mir)
ich möchte jetzt bei bedarf den inhalt dieser datei analysieren und muss
sie zu diesem zweck natürlich öffnen. (ich schreibe nie was hinein)
mfg
nullpunkt
Achso.
Dann ist es natürlich klar, dass du große Mengen des Inhalts im Arbeitsspeicher haben musst.
Trotzdem ist es vielleicht (je nach dem Format, in dem die Daten gespeichert sind) eine Überlegung wert, nicht alles auf einmal einzulesen, sondern Zeile für Zeile zu analysieren um RAM zu sparen.
hi,
so habs jetzt nochmals angepasst, sodass die verarbeitung
direkt in der schleife passiert (zeile um zeile).
spare einiges an zeit so, tiptop.
danke für eure tips : )
mfg
nullpunkt
Hallo!
Bin mir nicht ganz sicher, aber meines Wissens nach wird eine Array-Matrix in einem Stück angelegt, in diesem Fall mit Referenzen auf String(-Arrays). Bei 200MB-Dateien sind das bei durchschnittlich 100 Zeichen pro Zeile ca. 2mio. Array-Einträge. Evtl. hat das Framework an sich einfach nur Probleme, ein so großes Array zu erzeugen.
Nobody is perfect. I'm sad, i'm not nobody 🙁
List<String> Lines = new List<String>();
Wenn du weißt, dass du viele Zeilen in das Array einließt, empfiehlt es sich oftmals die Liste mit einen entsprechenden hohen Capacity-Wert im Konstruktor zu füllen. Das erspart lästiges umkopieren, wenn das interne Array überschritten wurde.
Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...