![]() |
Text Dateien (500mb+) in einen String einlesen
hallo,
ich öffne mal einen neuen thread da es sich hier um ein anderes problem handelt ich habe vor eine sql dump datei in einen string einzulesen und bestimmte zeichenkombinationen zu entfernen bzw zu ersetzen, diese dateien sind mit unter einige hundert megabyte groß nachdem ich nun eine ganze weile im netz und hier im forum gesucht habe bin ich auf folgende units gestoßen die zu meiner freude wirklich extrem schnell zeichenketten ersetzen können ![]() schwierig ist das ganze allerdings weil durch die größe der dateien möglicherweise nicht ausreichend arbeitsspeicher auf dem system zur verfügung steht hat jemand damit evtl schonmal erfahrungen gesammelt und kann mir sagen wie ich die datei am besten in einen string lade? |
Re: Text Dateien (500mb+) in einen String einlesen
Ich habe einen Vorschlag, der nicht so viel Speicher braucht:
1) Erstelle eine Instanz TFileStream, mit der man auf deine Datei zugreifen kann. 2) Geh mit for durch den Stream. Nach x Delimiterzeichen oder y KB kopierst du diesen Teil des Streams in einen String. 3) Dieser String wird bearbeitet. 4) Den bearbeiteten String in einen neuen Stream speichern, der dann die bearbeiteten Daten enthält. Den ganzen String auf einmal zum bearbeiten zu laden wäre faktisch "Selbstmord" für den Rechner, denn so große Datenmengen benötigen erstens sehr viel Zeit zum laden/bearbeiten und zweitens belasten sie den Arbeitsspeicher des Rechners sehr stark. |
Re: Text Dateien (500mb+) in einen String einlesen
ich hatte es anfangs mit folgendem code probiert
Delphi-Quellcode:
allerdings gibts dann wie erwartet die fehlermeldung
F:=TFileStream.Create(FileName,fmOpenRead);
try SetLength(Dumplist,F.Size); F.ReadBuffer(Dumplist[1],F.Size); finally F.Free; end; Dumplist:= FastReplace(FastReplace(Dumplist,'[[', '', False),']]', '', False); F:=TFileStream.Create(FileName,fmCreate); try F.Write(Dumplist[1],Length(Dumplist)); finally F.Free; end; showmessage('done'); // Dumplist:= FastReplace(Dumplist,'[[', '', False); ich hätte zu wenig arbeitsspeicher |
Re: Text Dateien (500mb+) in einen String einlesen
Die Warnung kommt wahrscheinlich zu Recht:
Delphi-Quellcode:
Denn an den markierten Stelle erstellst du einen String der Länge F.Size, was in unserem Fall hier 500*1024*1024 = 524288000 Bytes sein sollte.
F:=TFileStream.Create(FileName,fmOpenRead);
try SetLength(Dumplist,F.Size); // Problem hier F.ReadBuffer(Dumplist[1],F.Size); // Oder hier finally F.Free; end; Dumplist:= FastReplace(FastReplace(Dumplist,'[[', '', False),']]', '', False); F:=TFileStream.Create(FileName,fmCreate); try F.Write(Dumplist[1],Length(Dumplist)); finally F.Free; end; showmessage('done'); // Dumplist:= FastReplace(Dumplist,'[[', '', False); |
Re: Text Dateien (500mb+) in einen String einlesen
ja leider, dafür hat man aber eine 2mb datei in weniger als 1 sekunde abgearbeitet
|
Re: Text Dateien (500mb+) in einen String einlesen
Wenn du nicht weisst wie groß deine Datei ist, musst du diese Einbußen in Kauf nehmen oder mehr Code schreiben, zum Beispiel eine Abfrage, die prüft, ob die Datei auf einmal verarbeitet werden kann.
|
Re: Text Dateien (500mb+) in einen String einlesen
naja ich hab leider noch nie so wirklich mit filestreams gearbeitet,
da muss ich erstmal grübeln wie ich da den häppchenportionierer aufsetze |
Re: Text Dateien (500mb+) in einen String einlesen
so dank der hilfe einiger dp mitglieder bin ich mittlerweile
schon so weit das ich den stream stückchenweise einlesen kann ich weiß nun allerdings nicht wie ich FastReplace auf den Buffer anwenden kann
Delphi-Quellcode:
try
SrcStream:=TFileStream.Create(FileName,fmOpenread or fmShareDenyNone); DestStream:=TFileStream.Create(FileName,fmCreate); GetMem(Buffer, 1024); try while (SrcStream.Position < SrcStream.Size) do begin if SrcStream.Size - SrcStream.Position > BlockSize then Len := BlockSize else Len := SrcStream.Size - SrcStream.Position; SrcStream.ReadBuffer(Buffer^, Len); //FastReplace(Buffer^,'[[', '', False); DestStream.WriteBuffer(Buffer^, Len); end; finally FreeMem(Buffer); end; finally SrcStream.Free; DestStream.Free; end; |
Re: Text Dateien (500mb+) in einen String einlesen
Delphi-Quellcode:
Siehe Kommentare.
try
SrcStream:=TFileStream.Create(FileName,fmOpenread or fmShareDenyNone); DestStream:=TFileStream.Create(FileName,fmCreate); GetMem(Buffer, 1024); try while (SrcStream.Position < SrcStream.Size) do //was ist mit dem letzten Byte? begin if SrcStream.Size - SrcStream.Position > BlockSize then //Was ist BlockSize? //Sonst kann ich nicht //weiterhelfen Len := BlockSize else Len := SrcStream.Size - SrcStream.Position; SrcStream.ReadBuffer(Buffer^, Len); //Rückgabewert speichern //ab hier würde ich nun weiter einlesen, aber überprüfen, ob die //zuletzt eingelesene SQL-Anweisung schon zu ende ist und dann nicht mehr //weiter einlesen, zu bisher gespeicherten Rückgabewert jeweils noch //dazuaddieren //Die Summe der Rückgabewerte ist nun die Anzahl der zu verarbeitenden //Bytes, bitte beachten //Buffer abarbeiten DestStream.WriteBuffer(Buffer^, Len); end; finally FreeMem(Buffer); end; finally SrcStream.Free; DestStream.Free; //wenn beim Erstellen des SrcStream ein Fehler auftritt, wurde DestStream noch nicht erstellt und es kommt zu einer AV end; |
Re: Text Dateien (500mb+) in einen String einlesen
blocksize ist wie folgt deklariert:
Delphi-Quellcode:
den rückgabewert aus readbuffer kann ich leider
const
BlockSize = 1024; nicht so einfach speichern
Delphi-Quellcode:
hier erhalte ich die fehlermeldung
Dumplist:= SrcStream.ReadBuffer(Buffer^, Len);
'inkompatible typen: string and procedure, untyped pointer or untyped parameter' |
Re: Text Dateien (500mb+) in einen String einlesen
Ich würde dann aber bei GetMem mehr nehmen (4096) als bei BlockSize (3072) und eben notfalls (ReAllocMem) Speicher nachladen, nicht immer.
Der Rückgabewert ist ein Integer, und zwar die Anzahl der tatsächlich gelesenen Bytes |
Re: Text Dateien (500mb+) in einen String einlesen
also zur zeit schaut das ganze wie folgt aus:
Code:
endet allerdings in einer Zugriffsverletzung unbekannter Herkunft =(
const
BlockSize = 1024; var SrcStream, DestStream: TFileStream; FileName, FileName2, Buffer: String; N, ChunkLen :integer; begin FileName:= 'dump1.txt'; FileName2:= 'dump2.txt'; SrcStream:=TFileStream.Create(FileName,fmOpenread or fmShareDenyNone); DestStream:=TFileStream.Create(FileName2,fmCreate); try N:=SrcStream.Size; while N>0 do begin if N>BlockSize then ChunkLen:=BlockSize else ChunkLen:=N; SetLength(Buffer,ChunkLen); srcStream.ReadBuffer(Buffer,ChunkLen); N:=N-ChunkLen; FastReplace(Buffer,'\n', '', False); DestStream.WriteBuffer(Buffer,Length(Buffer)); end; finally SrcStream.Free; DestStream.Free; end; |
Re: Text Dateien (500mb+) in einen String einlesen
Zitat:
Delphi-Quellcode:
WriteBuffer(Buffer[1], Length(Buffer))
|
Re: Text Dateien (500mb+) in einen String einlesen
nein das klappt leider auch noch nicht,
ich hab die abwandlung von jemanden aus einer newsgroup im orginal sah das ganze so aus: srcStream.ReadBuffer(PChar(Buffer),ChunkLen); und DestStream.WriteBuffer(PChar(Buffer),Length(Buffer )); allerdings ging das ganze so nicht durch den compiler |
Re: Text Dateien (500mb+) in einen String einlesen
Warum nimmst du nicht einfach Read oder Write oder [oh]ReadBuffer, WriteBuffer[/oh]
PS: Ich sehe keinen Grund, hier etwas anderes als Read oder Write zu verwenden, außer, du willst es dir unnötig kompliziert machen. |
Re: Text Dateien (500mb+) in einen String einlesen
ich nutze doch read & writebuffer ?
|
Re: Text Dateien (500mb+) in einen String einlesen
Nehm doch
![]() ![]() Ich weiß nicht, wozu es überhuptpt die ...Buffer gibt, jedenfalls scheint mit nach Studieren der OH, dass sie eigentlich das gleiche wie Read und Write machen. Aber nimm lieber die normalen Read und Write. |
Re: Text Dateien (500mb+) in einen String einlesen
wahrscheinlich stell ich mich einfach zu dumm an
Delphi-Quellcode:
erzeugt auch eine zugriffsverletzung
srcStream.Read(Buffer,ChunkLen);
N:=N-ChunkLen; DestStream.Write(Buffer[1],Length(Buffer)); |
Re: Text Dateien (500mb+) in einen String einlesen
Du musst es beim Lesen genauso wie beim schreiben machen, Buffer[1] und nicht Buffer. Das sollte man sich angewöhnen, wenn man bei Streams mit Strings arbeitet.
![]() [edit=Admin]BBCode korrigiert. Mfg, Daniel[/edit] |
Re: Text Dateien (500mb+) in einen String einlesen
oh danke für deine gedult *gg*
auf jeden fall gibts nun keine zugriffsverletzung mehr, allerdings wenn ich nun versuche die inhalte aus dem buffer auf folgendem weg zu parsen dann erhalte ich ein wildes ascii kaos
Code:
SetLength(Buffer,ChunkLen);
srcStream.Read(Buffer[1],ChunkLen); N:=N-ChunkLen; DumpFile:= FastReplace(Buffer[1],'\n', '', False); DestStream.Write(DumpFile,Length(Buffer)); |
Re: Text Dateien (500mb+) in einen String einlesen
DumpFile :shock: Die Variable war in deinem Letzten Code noch gar nicht drin :(
Folgendes gilt, wenn es ein String ist, was ich vermute:
Delphi-Quellcode:
1. Du solltest statt Length(Buffer) Length(DumpFile) verwenden, ich nehme an, dass die beiden unterschiedliche Größen haben wegen dem
DestStream.Write(DumpFile,Length(Buffer));
Delphi-Quellcode:
2. Außerdem habe ich dir bereits gesagt, dass du bei Read und Write in einen String nicht den Pointer verwenden sollst, sondern die Daten, auf die er zeigt. Also nimm DumpFile[1] statt DumpFile
DumpFile:= FastReplace(Buffer[1],'\n', '', False);
Dann wird daraus
Delphi-Quellcode:
PS: Meine OH kennt FastReplace nicht. Hast du die selbst geschrieben oder gibt es die erst bei neueren Delphi-Versionen?
DestStream.Write(DumpFile[1],Length(DumpFile));
|
Re: Text Dateien (500mb+) in einen String einlesen
mach es doch mit memory mapped files ! dann kümmert windows sich ums caching und du arbeitest mit der datei alsob du sie komplett im speicher hättest
|
Re: Text Dateien (500mb+) in einen String einlesen
nabends,
ich möchte euch nochmal für eure hilfe und gedult danken, im großen und ganzen läuft das nun, die 500mb datei wird innerhalb von ein paar sekunden abgearbeitet, jetzt muss ich nur noch sicher stellen das strings die ersetzt werden sollen nicht durch die puffer größe zerstückelt werden, aber ich denke das bekomm ich auch alleine hin @FAlter die fastreplace funktion stammt aus einer unit deren link ich am anfang gepostet hab, damit lassen sich sehr schnell stringfunktionen abarbeiten, kann ich dir sehr empfehlen der aktuelle code schaut nun so aus:
Delphi-Quellcode:
const
BlockSize = 1024; var SrcStream, DestStream: TFileStream; FileName, FileName2, Buffer: String; N, ChunkLen: Integer; begin FileName:= 'dump.txt'; FileName2:= 'dump2.txt'; try SrcStream:=TFileStream.Create(FileName,fmOpenread or fmShareDenyNone); DestStream:=TFileStream.Create(FileName2,fmCreate); N:=SrcStream.Size; while N>0 do begin if N>BlockSize then ChunkLen:=BlockSize else ChunkLen:=N; SetLength(Buffer,ChunkLen); SrcStream.Read(Buffer[1],ChunkLen); Buffer:= FastReplace(Buffer,'\n', '', False); N:=N-ChunkLen; DestStream.Write(Buffer[1],Length(Buffer)); end; finally SrcStream.Free; DestStream.Free; end; |
Re: Text Dateien (500mb+) in einen String einlesen
@supermuckl
davon hör ich nun das erste mal, wüßte nicht das es sowas auch gibt naja ich werds auch nochmal probieren |
Re: Text Dateien (500mb+) in einen String einlesen
würde sich bestimmt lohnen..
man nennt es auch MMF abgekürzt.. falls du hilfe brauchst findest ein paar threads hier im forum oder frag mich.. hab da nen großes projekt under linux und windows gemacht mit MMF |
Re: Text Dateien (500mb+) in einen String einlesen
ich hab schon ein wenig rumgesucht und folgenden thread gefunden:
![]() hast du den code von Christian Seehase auch genutzt? |
Re: Text Dateien (500mb+) in einen String einlesen
naja ich hab mir ne komplette klasse selbst geschrieben ( 25kb )
ausserdem auch für linux.. das is nimmer mit einem stück code zu vergleichen aber die grundzüge sind die richtigen .. ist genau das worauf es aufbaut |
Re: Text Dateien (500mb+) in einen String einlesen
hm
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:37 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz