Einführung
TextFile / Read
File / BlockRead
TFileStream
TFileStream / TReader (ab Delphi 3)
Die Aufgabe ist es eine Datei zeichenweise zu lesen. Es gibt verschiedene Methoden das zu realisieren, ich habe hier 4 davon aufgeführt und dabei die Geschwindigkeiten verglichen.
Vorweg gleich die Zeiten in Sekunden, um 30 MByte zu lesen:
| Methode | Zeit |
| TextFile / Read | 8,03 |
| File / BlockRead | 7,92 |
| TFileStream | 327,22 |
| TFileStream / TReader | 8,55 |
Rahmenbedingungen: Delphi 3.02 Professional, Programm außerhalb der IDE gestartet, 30MByte-Datei, Rechner: PII-300, Ultrawide-SCSI.
Allgemeine Deklarationen:
const BufferSize = 4096; TestFilename = 'C:\TestFile.txt'; |
Die Methode mit Read funktioniert eigentlich am besten, man sollte jedoch beim Erzeugen einen großen Puffer anlegen.
Wichtig ist, daß Buffer solange zur Verfügung steht, bis CloseFile aufgerufen wird.
function Methode1:Integer;
var
f : TextFile;
Buffer : Pointer;
Ch : Char;
i : Integer;
begin
Result:=0;
GetMem(Buffer,BufferSize);
try
AssignFile(f,TestFilename);
SetTextBuf(f,Buffer^,BufferSize);
Reset(f);
try
while Not Eof(f) do begin
Read(f,ch);
Inc(Result);
end;
finally
CloseFile(f);
end;
finally
FreeMem(Buffer,BufferSize);
end;
end; |
Blockread ist ein ganz wenig schneller, der Programmieraufwand ist größer, da man sich hier selber um die Verwaltung des Puffers kümmern muß. (Pufferende prüfen, Dateiende prüfen, ...)
In BufferCount steht die Anzahl der wirklich gelesenen Bytes.
function Methode2:Integer;
type
PBuffer = ^TBuffer;
TBuffer = array[0..BufferSize-1] of Char;
var
f : File;
Buffer : PBuffer;
BufferCount : Integer;
BufferPos : Integer;
function Eof:Boolean;
begin
if BufferPos>=BufferCount then begin { einlesen Puffer }
BlockRead(f,Buffer^,BufferSize,BufferCount);
BufferPos:=0;
end;
Result:=BufferCount=0;
end;
function Read:Char;
begin
if Eof then raise Exception.Create('Dateiende erreicht');
Result:=Buffer^[BufferPos];
Inc(BufferPos);
end;
var
i : Integer;
Ch : Char;
begin
Result:=0;
GetMem(Buffer,BufferSize);
try
AssignFile(f,TestFilename);
Reset(f,1);
{ Puffer initialisieren }
BufferCount:=BufferSize;
BufferPos:=BufferSize;
try
while Not Eof do begin
Ch:=Read;
Inc(Result);
end;
finally
CloseFile(f);
end;
finally
FreeMem(Buffer,BufferSize);
end;
end; |
FileStream alleine ist ziemlich uneffektiv, die Puffergröße ist hier von der Windows-API abhängig. Ergebnis 40-fache Zugriffszeit.
function Methode3:Integer;
var
f : TFileStream;
Ch : Char;
i : Integer;
begin
Result:=0;
f:=TFileStream.Create(TestFilename,fmOpenRead);
try
for i:=0 to f.Size-1 do begin
f.Read(Ch,SizeOf(Ch));
Inc(Result);
end;
finally
f.Free;
end;
end; |
TReader sorgt für einen gepufferten Zugriff. Es lassen sich beliebige Strukturen in beliebiger Reihenfolge lesen. Für sequentielle Nicht-Char Dateizugriffe eine ideale Lösung. Diese Methode ist nur wenig langsamer als Methode 1 und 2.
function Methode4:Integer;
var
f : TFileStream;
r : TReader;
Ch : Char;
i : Integer;
begin
Result:=0;
f:=TFileStream.Create(TestFilename,fmOpenRead);
try
r:=TReader.Create(f,BufferSize);
try
for i:=0 to f.Size-1 do begin
r.Read(Ch,SizeOf(Ch));
Inc(Result);
end;
finally
r.Free;
end;
finally
f.Free;
end;
end; |
| Mail me at webmaster@pjh2.de. | Disclaimer |