Laden...

wachsende datei einlesen

Erstellt von Nullpunkt vor 15 Jahren Letzter Beitrag vor 15 Jahren 1.309 Views
N
Nullpunkt Themenstarter:in
277 Beiträge seit 2005
vor 15 Jahren
wachsende datei einlesen

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.

  • ich erhalte keine exception.
  • os: win server 2003
  • user: Administrator

was kann ich tun?

mfg nullpunkt

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo Nullpunkt,

wenn der FileShare-Modus von Writer- und Reader-Programm zueinander passen, sollte es kein Problem sein, die Datei zu lesen.

herbivore

N
Nullpunkt Themenstarter:in
277 Beiträge seit 2005
vor 15 Jahren

hi herbivore,
ups, das habe ich übersehen. danke, nun klappts wie am schnürchen.

mfg
nulllpunkt

N
Nullpunkt Themenstarter:in
277 Beiträge seit 2005
vor 15 Jahren

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

S
248 Beiträge seit 2008
vor 15 Jahren

Hi Nullpunkt,

File.ReadAllLines(string path, Encoding encoding)
oder
StreamReader.ReadLine()

könnten interessant sein.

Spo

5.742 Beiträge seit 2007
vor 15 Jahren

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.

N
Nullpunkt Themenstarter:in
277 Beiträge seit 2005
vor 15 Jahren

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

S
248 Beiträge seit 2008
vor 15 Jahren

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

1.820 Beiträge seit 2005
vor 15 Jahren

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 🙁

N
Nullpunkt Themenstarter:in
277 Beiträge seit 2005
vor 15 Jahren

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

5.742 Beiträge seit 2007
vor 15 Jahren

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.

N
Nullpunkt Themenstarter:in
277 Beiträge seit 2005
vor 15 Jahren

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

5.742 Beiträge seit 2007
vor 15 Jahren

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.

N
Nullpunkt Themenstarter:in
277 Beiträge seit 2005
vor 15 Jahren

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

5.742 Beiträge seit 2007
vor 15 Jahren

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.

N
Nullpunkt Themenstarter:in
277 Beiträge seit 2005
vor 15 Jahren

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

1.820 Beiträge seit 2005
vor 15 Jahren

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 🙁

3.971 Beiträge seit 2006
vor 15 Jahren
  
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...