Files & Streams
By default ({$I+}) I/O errors raise EInOutError (with SysUtils) or a run-time error.
20.1 File kinds
TextFile (or Text) lines of characters; read/write with Readln/Writeln file of TRecord fixed-size binary records; random access raw bytes in blocks: BlockRead/BlockWrite TFileStream, TMemoryStream,...
object-oriented binary I/O (unit Classes)
20.2 Text files
AssignFile(F, Name) bind a file variable to a name (Assign in TP/ISO modes) open existing file for reading (typed/untyped: read/write) create or truncate open a text file for appending flush and close (Close in TP mode) Eof(F), Eoln(F) end of file / end of line write buffered data SetTextBuf(F, Buf) larger buffer for faster text I/O
program TextFiles;
{$mode objfpc}{$H+}
var
F: TextFile;
Line: string;
I: Integer;
begin
AssignFile(F, 'notes.txt'); // associate the variable with a file name
Rewrite(F); // create/truncate for writing
for I := 1 to 3 do
Writeln(F, 'Line ', I);
CloseFile(F);
Append(F); // open for appending
Writeln(F, 'Appended line');
CloseFile(F);
Reset(F); // open for reading
while not Eof(F) do
begin
Readln(F, Line);
Writeln(Line);
end;
CloseFile(F);
end.20.3 I/O error handling with IOResult
By default ({$I+}) I/O errors raise EInOutError (with SysUtils) or a run-time error. With {$I-} you check IOResult yourself:
IOResult resets to 0 after it is read — store it in a variable if you need it twice. Modern code usually checks FileExists first and uses exceptions.
AssignFile(F, 'missing.txt');
{$I-}
Reset(F);
{$I+}
if IOResult <> 0 then
Writeln('Cannot open file')
else
begin
// ... read ...
CloseFile(F);
end;20.4 Typed files (random access)
FilePos(F) returns the current record number; Truncate(F) cuts the file at the current position.
program TypedFiles;
{$mode objfpc}{$H+}
type
TProduct = record
Id: Integer;
Name: string[30]; // ShortString: typed files cannot contain managed types
Price: Double;
end;
var
F: file of TProduct;
P: TProduct;
I: Integer;
begin
AssignFile(F, 'products.dat');
Rewrite(F);
for I := 1 to 3 do
begin
P.Id := I;
P.Name := 'Product ' + Chr(Ord('A') + I - 1);
P.Price := I * 9.99;
Write(F, P);
end;
Writeln('Records: ', FileSize(F)); // 3
Seek(F, 1); // record numbers are 0-based
Read(F, P);
Writeln(P.Id, ' ', P.Name, ' ', P.Price:0:2); // 2 Product B 19.98
Seek(F, 1); // update record 1 in place
P.Price := 15.00;
Write(F, P);
CloseFile(F);
end.20.5 Untyped files: copying a file
Always pass the record size (1) to Reset/Rewrite for untyped files; the default is 128 bytes.
procedure CopyFileBlocks(const SrcName, DstName: string);
var
Src, Dst: file;
Buf: array[0..65535] of Byte;
NRead, NWritten: Integer;
begin
AssignFile(Src, SrcName);
Reset(Src, 1); // record size 1 byte
try
AssignFile(Dst, DstName);
Rewrite(Dst, 1);
try
repeat
BlockRead(Src, Buf, SizeOf(Buf), NRead);
BlockWrite(Dst, Buf, NRead, NWritten);
until (NRead = 0) or (NWritten <> NRead);
finally
CloseFile(Dst);
end;
finally
CloseFile(Src);
end;
end;20.6 Streams
abstract base: Read, Write, ReadBuffer, WriteBuffer, Seek, Position, Size, CopyFrom in-memory buffer; LoadFromFile, SaveToFile stream over a string read embedded resources buffered file access (Delphi 10.1+; FPC's BufStream unit offers TReadBufStream/TWriteBufStream) TStreamReader / TStreamWriter text over streams with encodings (Delphi System.Classes; in FPC use TStringList or text files)
program Streams;
{$mode objfpc}{$H+}
uses Classes, SysUtils;
var
FS: TFileStream;
N: Integer;
X: Double;
begin
FS := TFileStream.Create('data.bin', fmCreate);
try
N := 12345;
X := 2.5;
FS.WriteBuffer(N, SizeOf(N));
FS.WriteBuffer(X, SizeOf(X));
finally
FS.Free;
end;
FS := TFileStream.Create('data.bin', fmOpenRead or fmShareDenyWrite);
try
FS.ReadBuffer(N, SizeOf(N));
FS.ReadBuffer(X, SizeOf(X));
Writeln(N, ' ', X:0:1, ' size=', FS.Size); // 12345 2.5 size=12
finally
FS.Free;
end;
end.20.7 TStringList as a text file tool
For real INI files use TIniFile/TMemIniFile (unit IniFiles).
uses Classes, SysUtils;
var
SL: TStringList;
begin
SL := TStringList.Create;
try
if FileExists('config.ini') then
SL.LoadFromFile('config.ini');
SL.Values['theme'] := 'dark'; // key=value lines
SL.Add('# saved ' + DateTimeToStr(Now));
SL.SaveToFile('config.ini');
finally
SL.Free;
end;
end.20.8 Files and directories
Routine (SysUtils) FileExists, DirectoryExists DeleteFile, RenameFile delete, rename
CreateDir, ForceDirectories, RemoveDir GetCurrentDir, SetCurrentDir
ExtractFileName, ExtractFilePath, ExtractFileExt, ChangeFileExt
IncludeTrailingPathDelimiter, PathDelim, ConcatPaths (FPC)
GetTempDir, GetAppConfigDir (FPC), GetHomePath (Delphi) FileAge, FileSetDate, FileGetAttr
Delphi's System.IOUtils offers record-style APIs: TFile.ReadAllText, TFile.WriteAllLines, TDirectory.GetFiles(Path, '*.pas', TSearchOption.soAllDirectories), TPath.Combine. Lazarus provides the FileUtil and LazFileUtils units (FindAllFiles, CopyFile, DeleteDirectory).
uses SysUtils;
var
SR: TSearchRec;
begin
if FindFirst('*.pas', faAnyFile, SR) = 0 then
try
repeat
if (SR.Attr and faDirectory) = 0 then
Writeln(SR.Name:30, SR.Size:10);
until FindNext(SR) <> 0;
finally
FindClose(SR);
end;
end.