AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Datei im Speicher zeilenweise lesen

Ein Thema von Luckie · begonnen am 12. Okt 2005 · letzter Beitrag vom 12. Okt 2005
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#1

Datei im Speicher zeilenweise lesen

  Alt 12. Okt 2005, 03:33
Ich lade so:
Delphi-Quellcode:
var
  hMemory : THandle;
  pMemory : pointer;
begin
  hFile := CreateFile(szFilename,GENERIC_READ or GENERIC_WRITE,
    FILE_SHARE_READ or FILE_SHARE_WRITE,nil,OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL,0);

  // Speicher anfordern, & Dateiinhalt lesen
  hMemory := GlobalAlloc(GMEM_MOVEABLE or GMEM_ZEROINIT,MEMSIZE);
  pMemory := GlobalLock (hMemory);

  ReadFile(hFile,pMemory^,MEMSIZE-1,SizeReadWrite,nil);
eine Datei in den Speicher. Es handelt sich dabei um eine Textdatei, die ich nun zeilenweise lesen muss. Wie kann ich das nun am einfachsten bewerkstelliegen ohne jedes Byte einzeln zu lesen und nach einem Zeilenumbruch zu suchen? Wichjtig: Es muss mit WinAPI Funktionen geschehen, das heißt eine StringListe oder ähnliches kann ich nicht benutzen.

Hintergrund ist der, dass die Datei auch größer sein kann und ich nicht für jede Zeile lesend auf den Datenträger zugreifen will, da dies zum einen sehr langsam ist, das Betriebssystem sonst andauernd mit lesen vom Datenträger beschäftigt wäre und bei Notebooks kommt hinzu, dass der dauernde Zugriff auf den Datenträger sehr viel Strom verbraucht. Deshalb kann ich auch nicht mit AssignFile und Readln arbeiten.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Benutzerbild von BrunoT
BrunoT

Registriert seit: 23. Jan 2003
Ort: Sandbeiendorf
360 Beiträge
 
Delphi 8 Professional
 
#2

Re: Datei im Speicher zeilenweise lesen

  Alt 12. Okt 2005, 06:20
Hi Luckie,

lies es doch gleich in eine verkettete Liste Zeilenweise ein.

mfg

BrunoT
Holger

EDV- Ende der Vernunft
Meine Calcedit-Kompo
  Mit Zitat antworten Zitat
Benutzerbild von Flocke
Flocke

Registriert seit: 9. Jun 2005
Ort: Unna
1.172 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#3

Re: Datei im Speicher zeilenweise lesen

  Alt 12. Okt 2005, 07:29
Um es dir einfach zu machen, könntest du wirklich einfach ein Text bzw. TextFile mit ReadLn benutzen. Die Puffergröße kannst du mit System.SetTextBuf vergrößern (z.B. auf 64K). Das sollte die Datenträgerzugriffe auf ein Minimum beschränken.

Ansonsten müsstest du dir wirklich jedes Zeilenende selbst suchen. Würde natürlich zur Not auch gehen, indem du direkt einen String als Puffer nimmst, also etwa so (ungetestet):

Delphi-Quellcode:
const
  BUFSIZE = 65536;

// Initialisierung
function InitLine(hFile: THandle; var FileBufStr: string): boolean;
var
  GotBytes: cardinal;
begin
  SetLength(FileBufStr, BUFSIZE);
  Result := ReadFile(hFile, @FileBufStr[1], BUFSIZE, GotBytes, nil);
  if Result then
    SetLength(FileBufStr, GotBytes)
  else
    FileBufStr := '';
end;

// Zeile lesen nach Output, liefert FALSE bei EOF, sonst TRUE
function GetLine(hFile: THandle; var FileBufStr: string; var Output: string): boolean;
var
  P, OldLen: integer;
  GotBytes: cardinal;
begin
  P := Pos(#10, FileBufStr);
  while P = 0 do
  begin
    OldLen := Length(FileBufStr);
    SetLength(FileBufStr, OldLen + BUFSIZE);
    if not ReadFile(hFile, @FileBufStr[OldLen], BUFSIZE, GotBytes, nil) then
      break;
    if GotBytes = 0 then
      break;
    SetLength(FileBufStr, OldLen + GotBytes);
    P := Pos(#10, FileBufStr);
  end;

  if P > 0 then
  begin
    Result := true;
    Output := Copy(FileBufStr, 1, P - 1);
    Delete(FileBufStr, 1, P);
  end
  else
  begin
    Result := FileBufStr <> '';
    Output := FileBufStr;
    FileBufStr := '';
  end;
end;
Volker
Besucht meine Garage
Aktuell: RtfLabel 1.3d, PrintToFile 1.4
  Mit Zitat antworten Zitat
ripper8472

Registriert seit: 17. Aug 2003
275 Beiträge
 
#4

Re: Datei im Speicher zeilenweise lesen

  Alt 12. Okt 2005, 07:47
die c standardfunktionen fuer zeilenweises lesen lesen auch nur zeichen fuer zeichen.
du koenntest das aber optimieren, wenn du ein bisschen mit zeigern arbeitest.
zeiger auf den anfang setzen und dann immer weitergehen bis ein umbruch kommt. dann von anfang bis hier als zeile betrachten.
dann das gleiche spiel nochmal.
Christoph
  Mit Zitat antworten Zitat
alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#5

Re: Datei im Speicher zeilenweise lesen

  Alt 12. Okt 2005, 08:21
Entschuldigt mal bitte, was soll den dieses 'lesen auch nur Zeichen für Zeichen'. Das macht doch keine Funktion mehr: Windows sorgt dafür, das die Daten blockweise eingelesen werden (üblicherweise in Größe der Systempage, also 8kb). Das ist so ziemlich optimal. Wenn ich dann bis zum nächsten Zeilenende lesen will, dann bleibt mir ja wohl nichts anderes übrig, als Zeichen für Zeichen zu vergleichen. Windows sorgt z.B. bei einem Stream schon dafür, das das recht flott geht.

Damit deine SW stabil bleibt, musst Du eine kleine Mittelschicht implementieren, die aus Windows-Seiten einzelne Zeilen macht. Wenn Du weisst, das eine Zeile maximal 1000 Zeichen lang ist, dann hast Du zwei Buffer a 1000 Zeilen, die Du abwechselnd nachliest:
Wenn Buffer A 'fast' am Ende ist, lässt Du die folgende Seite in Buffer 'B' einlesen und umgekehrt.
Die beiden Buffer liegen im Speicher aber direkt hintereinander, sodass man A und B als ein Array implementiert. BufferA zeigt dann z.B. auf Array[0] und BufferB auf Array[1000].

Du hast dann noch eine (Inline-) Funktion GetChar, die dir Array[X] zurückliefert, X erhöht und ggf A bzw. B nachlädt.

Das wars. Du merkst Dir also 'X', liest per GetChar bis zum nächsten CR/LF und kopierst Array [Xstart]...Array [X-2] in dein Resultatstring. Dabei musst Du nur darauf achten, ob X<XStart ist, dann sind es nämlich zwei Move-Operationen, ansonsten nur eine.
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat
Benutzerbild von BrunoT
BrunoT

Registriert seit: 23. Jan 2003
Ort: Sandbeiendorf
360 Beiträge
 
Delphi 8 Professional
 
#6

Re: Datei im Speicher zeilenweise lesen

  Alt 12. Okt 2005, 08:55
Hi Luckie,

ich will mal für meinen Lösungsvoeschlag ein Beispiel anhängen:

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
type
  Zeiger = ^tZeiger;
  tZeiger = record
    Nr:Integer;
    Str: string;
    Ptr: zeiger;
  end;
var
  StartZ, HilfPtr1,HilfPtr2: Zeiger;

procedure in_Liste(i:Integer;s: string);
begin
  New(HilfPtr1);
  if i=0 then
  Begin
    New(HilfPtr2);
    StartZ:=HilfPtr2;
  end;
  HilfPtr1^.Nr := i;
  HilfPtr1^.Str := s;
  HilfPtr2^.Ptr := HilfPtr1;
  HilfPtr2:=HilfPtr1;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  T: Textfile;
  s: string;
  i:integer;
begin
  i:=0;
  memo1.Clear;
  Assignfile(t, 'test.txt');
  reset(t);
  while not eof(t) do
  begin
    readln(t, s);
    in_Liste(i,s);
    inc(i);
  end;
  closefile(t);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  HilfPtr1 := StartZ;
  while (HilfPtr1 <> nil) do
  begin
    HilfPtr1 := HilfPtr1^.Ptr;
    if HilfPtr1 <> nil then
      Memo1.Lines.Add(HilfPtr1.Str);
  end;
end;

end.
///Der einzige "Nachteil" ist, dass die Textdatei von hinten nach vorn im Speicher liegt.
[edit] ich habe es jetzt umgedreht. Die Daten liegen jetzt in der richtigen Reihenfolge [/edit]
//Aber das lässt sich ja ändern.

mfg

BrunoT
Angehängte Dateien
Dateityp: zip quelle_153.zip (6,9 KB, 16x aufgerufen)
Dateityp: zip testprog_161.zip (200,6 KB, 13x aufgerufen)
Holger

EDV- Ende der Vernunft
Meine Calcedit-Kompo
  Mit Zitat antworten Zitat
Olli
(Gast)

n/a Beiträge
 
#7

Re: Datei im Speicher zeilenweise lesen

  Alt 12. Okt 2005, 10:18
Micha, es ist völlig in Ordnung wenn du zeichenweise einliest. Wie oben erwähnt, tun dies andere Libs auch. Damit wird die Performance nicht wirklich gesenkt
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#8

Re: Datei im Speicher zeilenweise lesen

  Alt 12. Okt 2005, 11:23
Zitat von Flocke:
Um es dir einfach zu machen, könntest du wirklich einfach ein Text bzw. TextFile mit ReadLn benutzen. Die Puffergröße kannst du mit System.SetTextBuf vergrößern (z.B. auf 64K). Das sollte die Datenträgerzugriffe auf ein Minimum beschränken.

Ansonsten müsstest du dir wirklich jedes Zeilenende selbst suchen. Würde natürlich zur Not auch gehen, indem du direkt einen String als Puffer nimmst, also etwa so (ungetestet):
Jetzt bringst du mich ins Grübeln. Dein erster Vorschlag ist natürlich der einfachere zum Umsetzen. Aber du hast dir schon deie Mühe gemacht für deinen zweiten Vorschlag kompletten Code zu schreiben (Wäre übrigens nicht nötig gewesen, das hätte ich nämlich auch noch hinbekommen. Es ging mir nur um das Prinzip,), den will ich jetzt irgendwie auch nicht wegschmeißen. Mach mir die Entscheidung leichter und sagt mir einfach, dass die WinAPI Lösung, gegenüber der Pascal Lösung, performanter ist, dann nehme ich deinen schönen Code.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
opfer.der.genauigkeit

Registriert seit: 14. Feb 2005
66 Beiträge
 
#9

Re: Datei im Speicher zeilenweise lesen

  Alt 12. Okt 2005, 11:58
Hallo Luckie,

schau dir mal das an:

FileMapping:

http://msdn.microsoft.com/library/de...ilemapping.asp

evtl. ist das interessant für dich.
Stellen Sie sich bitte Zirkusmusik vor.
  Mit Zitat antworten Zitat
Olli
(Gast)

n/a Beiträge
 
#10

Re: Datei im Speicher zeilenweise lesen

  Alt 12. Okt 2005, 11:59
Zitat von Luckie:
Mach mir die Entscheidung leichter und sagt mir einfach, dass die WinAPI Lösung, gegenüber der Pascal Lösung, performanter ist, dann nehme ich deinen schönen Code.
Die dürften sich nicht viel nehmen. Aber da du die Datei mappen würdest und entsprechend als langen String im Speicher hast, kannst du auch mit einer Schleife durchgehen und die Zeilen extrahieren. Ich würde es übrigens wie folgt machen:

Ich gehe durch den Puffer und ersetze alle #13 durch #0, danach habe ich ein typisches "Array" von nullterminierten Strings und muß ähnliche Methoden anwenden wie bei REG_MULTI_SZ. Wenn der Puffer R/O ist, dann würde ich selbstverständlich nur nach #13 suchen ohne zu ersetzen und dann eben die entsprechenden Anfangsoffsets und Endoffsets merken und mit lstrcpyn() kopieren.

Was du keinesfalls machen solltest ist, einen String zu nehmen und die Zeichen jeweils zeichenweise an den String anzuhängen. Dadurch würde intern viel mehr ablaufen als das einfach Kopieren einer Zeile in einen String oder Puffer.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:28 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz