Autor Beitrag
Calibu
Hält's aus hier
Beiträge: 11



BeitragVerfasst: 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. :evil:
Vielen Dank schonmal...

Calibu
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6393
Erhaltene Danke: 147

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 75

Win XP
Delphi 7 / 8 Enterprise
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1112



BeitragVerfasst: 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 Threadstarter
Hält's aus hier
Beiträge: 11



BeitragVerfasst: 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 :D !
Calibu Threadstarter
Hält's aus hier
Beiträge: 11



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1112



BeitragVerfasst: Di 26.10.04 12:52 
Ähm ... + (in Worten: Plus)? Oder hab ich da was falsch verstanden? :shock:

_________________
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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 75

Win XP
Delphi 7 / 8 Enterprise
BeitragVerfasst: Di 26.10.04 13:09 
.Chef hat folgendes geschrieben:
Ähm ... + (in Worten: Plus)? Oder hab ich da was falsch verstanden? :shock:


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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6393
Erhaltene Danke: 147

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: 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 Threadstarter
Hält's aus hier
Beiträge: 11



BeitragVerfasst: 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 Threadstarter
Hält's aus hier
Beiträge: 11



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6393
Erhaltene Danke: 147

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: 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:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
procedure TForm1.btnDateiLadenClick(Sender: TObject);
var
  buff : array [0..4999of char; // Ein paar tausend Bytes
  f : file;
  Eingelesen : Integer;
begin
  if dlgOpen.Execute then begin  // Datei öffnen
    AssignFile(f, dlgOpen.FileName);
    Reset(f, 1); // Recordgröße auf 1 setzen
    BlockRead(F, buff, SizeOf(buff), Eingelesen); // Block von 4999 Byte einlesen
    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.

ausblenden 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:= ''// Achtung, das ist nur hier als Beispiel. In deiner Routine muss das woanders gemacht werden,
          // da du ja noch mehr buffer einlesen musst.
  for cnt := 0 to 4999 do begin
    if buff[cnt] = ';' then begin
      // Eine Zahl wurde vollständig eingelesen. Mit der muss jetzt was gemacht werden
      // Danach wieder :
      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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1112



BeitragVerfasst: Di 26.10.04 21:59 
Ich kann das Drama nicht mehr mit anschauen. :roll: ... ;-)

ausblenden 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 Threadstarter
Hält's aus hier
Beiträge: 11



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6393
Erhaltene Danke: 147

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: 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 Threadstarter
Hält's aus hier
Beiträge: 11



BeitragVerfasst: 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

ausblenden volle Höhe Delphi-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:
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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1112



BeitragVerfasst: Fr 29.10.04 23:05 
Weil du jedes Zeichen einzeln liest anstatt alle auf einmal. :nixweiss:

_________________
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 Threadstarter
Hält's aus hier
Beiträge: 11



BeitragVerfasst: Fr 29.10.04 23:08 
Okay. Muss ich wohl Kompromisse eingehen. So`n Mist. Aber trotzdem danke!
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: 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.