Autor |
Beitrag |
Calibu
Hält's aus hier
Beiträge: 11
|
Verfasst: Mo 25.10.04 12:46
Hallo Delphianer,
ich habe folgendes Problem:
Ich möchte gern eine Textdatei auslesen. In dieser Datei stehen Zahlen, und zwar ein- bis dreistellig, getrennt durch Semikolon, Leerzeichen oder Doppelpunkt (das kann ich mir beim erstellen aussuchen). Diese Zahlen möchte ich in einen Chart eintragen, müsste dazu aber erstmal Stück für Stück auslesen, damit es nicht gleich beim ersten Semikolon errort. Mit "POS..." bin ich nicht sehr weit gekommen. Da die Datei aber insgesamt bis zu 10Mio. Zahlen enthält, weiß ich nicht mehr weiter. Ich bräuchte auch nur einen Ansatz, da ich jetzt schon Wochen damit beschäftigt bin und blind werde für andere Wege.
Vielen Dank schonmal...
Calibu
|
|
jasocul
      
Beiträge: 6393
Erhaltene Danke: 147
Windows 7 + Windows 10
Sydney Prof + CE
|
Verfasst: Mo 25.10.04 12:52
Einzelne Zeichen einlesen geht mit Read. Das dürfte bei dem Datenumfang aber zu langsam sein. Schau dir lieber Blockread in der OH an.
Wenn du damit nicht zurecht kommst, sag bescheid. Ich hab zuhause sowas auch schon gebraucht. Könnte dir die Sourcen zur Verfügung stellen.
|
|
P_G
      
Beiträge: 75
Win XP
Delphi 7 / 8 Enterprise
|
Verfasst: Mo 25.10.04 12:59
Hi,
Du könntest mit Commatext zunächst die einzelnen Zahlen in eine ListBox oder ein StringList-Objekt übertragen. Dort sind die Daten dann indiziert und man kann leicht auf sie zugreifen. Zum Beispiel:
1. Text-Datei in ein Memo-Feld laden. (LoadfromFile)
2. ListBox1.Items.CommaText := Memo1.Text;
Commatext nimmt jede Leerstelle als Marker für einen neuen Listeneintrag in die ListBox. Du kannst diese Funktion aber auch umschreiben, um andere Marker zu benutzen.
3. Durch die einzelnen Listeneintrage iterieren um die Daten in ein Chart zu übertragen.
Gruß, P_G
|
|
.Chef
      
Beiträge: 1112
|
Verfasst: Mo 25.10.04 13:03
Bei 10 MB ist das keine gute Idee. Da ist ein Verfahren mit Dateipointer wie BlockRead oder TFileStream schon geeigneter.
_________________ Die Antworten auf die 5 häufigsten Fragen:
1. Copy(), Pos(), Length() --- 2. DoubleBuffered:=True; --- 3. Application.ProcessMessages bzw. TThread --- 4. ShellExecute() --- 5. Keine Vergleiche von Real-Typen mit "="!
|
|
Calibu 
Hält's aus hier
Beiträge: 11
|
Verfasst: Mo 25.10.04 15:01
Hallo...
mit so schneller und umfangreicher Hilfe hab ich jetzt gar nicht gerechnet. Wahnsinn.
Vielen Dank. Ich werd dann posten, wenn ich weiter bin  !
|
|
Calibu 
Hält's aus hier
Beiträge: 11
|
Verfasst: Di 26.10.04 12:21
Hallo an alle,
mit BlockRead hat ausgezeichnet funktioniert. Kann jedes Zeichen einzeln einlesen und gebe es momentan in einem Edit wieder. Jetzt eröffnet sich mir allerdings nächstes Problem:
Wie setze ich die Zeichen die zusammengehören wieder zusammen? Also die Zahlen zwischen den Semikolons?!
Vielen Dank!
|
|
.Chef
      
Beiträge: 1112
|
Verfasst: Di 26.10.04 12:52
Ähm ... + (in Worten: Plus)? Oder hab ich da was falsch verstanden? 
_________________ Die Antworten auf die 5 häufigsten Fragen:
1. Copy(), Pos(), Length() --- 2. DoubleBuffered:=True; --- 3. Application.ProcessMessages bzw. TThread --- 4. ShellExecute() --- 5. Keine Vergleiche von Real-Typen mit "="!
|
|
P_G
      
Beiträge: 75
Win XP
Delphi 7 / 8 Enterprise
|
Verfasst: Di 26.10.04 13:09
.Chef hat folgendes geschrieben: | Ähm ... + (in Worten: Plus)? Oder hab ich da was falsch verstanden?  |
Ich nehme an, Calibu fragt sich, wie er die einzeln eingelesenen Zeichen automatisch wieder in zwei- bis dreistellige Zahlen zurückverwandelt. Mal abgesehen davon, daß dieser Weg doch wohl noch immer keinen indizierten Zugriff auf die einzelnen Zahlen zuläßt...
|
|
jasocul
      
Beiträge: 6393
Erhaltene Danke: 147
Windows 7 + Windows 10
Sydney Prof + CE
|
Verfasst: Di 26.10.04 13:15
Ich befürchte auch, dass er beim Blockread einen Block von einem Byte einliest.
Ich stelle heute abend mal ein kleines Beispiel für Blockread zur Verfügung.
|
|
Calibu 
Hält's aus hier
Beiträge: 11
|
Verfasst: Di 26.10.04 13:28
Hallo jasocul & P_G,
habt beide Recht. Ich lese die Datei jetzt Byte für Byte ein und habe jetzt das Problem, das ich bei z.B. 123;8;24;48... halt nicht die "1", "2" und "3" im Chart haben möchte, sondern die "123".
Danke
Calibu
|
|
Calibu 
Hält's aus hier
Beiträge: 11
|
Verfasst: Di 26.10.04 21:25
Hallo an alle,
also eine wahrscheinlich unschöne Lösung habe ich jetzt. Da ich weiß, das die Zeichen zwischen den Semikolons min. einstellig sind und max. 3stellig, lese ich solange Zeichen ein, bis ein Semikolon dran ist. In einem Edit werden dann die vorangegangen Zeichen hintereinander geschrieben und in Floating-Point-Values gewandelt. Aber das kann doch nicht die Lösung sein, oder?! Muss doch auch einfacher gehen?!
|
|
jasocul
      
Beiträge: 6393
Erhaltene Danke: 147
Windows 7 + Windows 10
Sydney Prof + CE
|
Verfasst: Di 26.10.04 21:41
Ich wollte ja eigentlich ein paar Sourcen bereitstellen. Aber mein Programm, in dem ich Blockread benutze, müsste zu sehr angepasst werden. Daher jetzt ein paar Häppchen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| procedure TForm1.btnDateiLadenClick(Sender: TObject); var buff : array [0..4999] of char; f : file; Eingelesen : Integer; begin if dlgOpen.Execute then begin AssignFile(f, dlgOpen.FileName); Reset(f, 1); BlockRead(F, buff, SizeOf(buff), Eingelesen); System.Close(F); end; end; |
Das ganze muss natürlich in einer Schleife laufen, bis alle Daten eingelesen wurden.
Innerhalb dieser Schleife musst du deine Daten verarbeiten.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| var cnt : Integer; s : String; begin s:= ''; for cnt := 0 to 4999 do begin if buff[cnt] = ';' then begin s := ''; end else begin s := s + buff[cnt]; end; end; end; |
Deine Probleme:
- Du musst da zwei Schleifen drum bauen. Eine für das BlockRead und eine innere zur Verarbeitung.
- Beim einlesen des buffers kann es sein, dass der buffer mitten in einer Zahl zu ende ist. Diese Zahl wird aber im nächsten BlockRead fortgesetzt.
Der wesentliche Vorteil:
- Es ist wesentlich schneller als jedes Zeichen einzeln einzulesen. Wenn du den buffer größer wählst geht es noch schneller. Aber 10MB gehen nicht.
Hoffentlich hilft dir das ein bisschen.
Zuletzt bearbeitet von jasocul am Mi 27.10.04 08:33, insgesamt 2-mal bearbeitet
|
|
.Chef
      
Beiträge: 1112
|
Verfasst: Di 26.10.04 21:59
Ich kann das Drama nicht mehr mit anschauen.  ...
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| var f : file; x, y : array of Byte; a, b, c : Integer; begin AssignFile(f,'test.txt'); Reset(f,1); SetLength(x,FileSize(f)); BlockRead(f,x[0],Length(x),c); CloseFile(f); SetLength(y,c div 2); b:=0; FillChar(y[a],c div 2,0); for a:=0 to c-1 do if x[a] = 59 then Inc(b) else y[b]:=y[b]*10+x[a]-48; SetLength(y,b+1); end; |
_________________ Die Antworten auf die 5 häufigsten Fragen:
1. Copy(), Pos(), Length() --- 2. DoubleBuffered:=True; --- 3. Application.ProcessMessages bzw. TThread --- 4. ShellExecute() --- 5. Keine Vergleiche von Real-Typen mit "="!
|
|
Calibu 
Hält's aus hier
Beiträge: 11
|
Verfasst: Di 26.10.04 22:12
Super! Genial!
Es funktioniert. Zumindest auf meinem Rechner. Für den Kopf brauch ich noch ein Weilchen.
Dankeschön!
|
|
jasocul
      
Beiträge: 6393
Erhaltene Danke: 147
Windows 7 + Windows 10
Sydney Prof + CE
|
Verfasst: Mi 27.10.04 08:12
@.chef:
So schlimm wars doch nun auch wieder nicht. Ich habe zwar gerade gesehen, dass ich beim Kopieren einen Fehler gemacht habe, aber deswegen musst du nicht gleich so doll hauen. Hab ich übrigens gerade korrigiert.
Und 10 MB komplett in ein dynamisches Array einzulesen, habe ich mich nicht getraut.
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Mi 27.10.04 09:03
Naja, hatte mal ein Programm, das hat ein dynamisch, über Pointer Addressiertes Array von 512 MB im Speicher gehalten. Hatte zwar dort seine Berechtigung, aber es funktioniert auch. Nur man sollte es eben vermeiden, wenn es nicht unbedingt notwendig ist.
(Im speziellen Fall gings um die bereits bekannten Primzahlen eines Primzahlen-Test-Programms, dass möglichst schnell sein sollte. Daher brauchte ich die Faktoren gleich im Speicher).
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Calibu 
Hält's aus hier
Beiträge: 11
|
Verfasst: Fr 29.10.04 23:01
Hallo nocheinmal!
Da ich Eure Lösung zwar funktionierte, ich es aber leider nicht so recht verstanden habe, hab ich mich selbst nocheinmal rangemacht. Auf die folgende Art und Weise funktioniert es auch ganz prima, und alles ohne Arrays. Allerdings braucht mein Rechner Ewigkeiten, bis der Chart fertig ist. Kann mir einer sagen woran das liegt??
Danke
Calibu
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:
| var Form1: TForm1; F: file of char; c: char; s: string; i, j: integer;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject); begin series1.Clear; opendialog1.Execute; assignfile(f, opendialog1.FileName); reset(f); j:= filesize(f); while not eof (f) do begin read(f, c); if (c <> ';') then begin s:= s + c; end else begin i:= strtoint(s); series1.AddY(i); s:= ''; end; end; closefile(f); end;
end. |
|
|
.Chef
      
Beiträge: 1112
|
Verfasst: Fr 29.10.04 23:05
Weil du jedes Zeichen einzeln liest anstatt alle auf einmal. 
_________________ Die Antworten auf die 5 häufigsten Fragen:
1. Copy(), Pos(), Length() --- 2. DoubleBuffered:=True; --- 3. Application.ProcessMessages bzw. TThread --- 4. ShellExecute() --- 5. Keine Vergleiche von Real-Typen mit "="!
|
|
Calibu 
Hält's aus hier
Beiträge: 11
|
Verfasst: Fr 29.10.04 23:08
Okay. Muss ich wohl Kompromisse eingehen. So`n Mist. Aber trotzdem danke!
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Fr 29.10.04 23:12
Eigentlich ganz einfach, wenn man weiß, wie Windows aus Dateien liest:
Jedes Readfile benötigt:
- Prüfen des Dateihandle
- Prüfen auf Korrektheit der Eingaben
- Finden der Datei im Dateiindex
- Suchen des richtigen Fragments
- Suchen des richtigen Sektors
- Lesen der angeforderten Menge in Blöcken von 64KB
- Füllen des Puffers mit den richtigen Informationen
Je kleiner also deine Blöcke sind, desto mehr Overhead erzeugst du.
Wenn du jedoch 16 MB auf einmal liest (dauert zwar rund 4 Sekunden) muss Windows nur einmal die ersten 3 Schritte durchführen. Die letzten 4 Schritte werden dann einfach wiederholt, wenn diese nötig sind.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|