Using FileStreams

On the previous page we showed how easy it is to use a StringList save a file of strings. The object-oriented way to use binary files is via the TFileStream class. You can compare the code here with the alternative approach for output and input. TFileStream and its ancestor TStream "wrap" the direct file-handling code in order to make it easier to use. We demonstrate the file modes fmCreate and fmOpenRead and leave it to you to try fmOpenWrite and fmOpenReadWrite.

This Lazarus demonstration shows how you can write and then read an assortment of different types. Explicit support for real numbers is missing, so we simply use the FloatToStr and StrToFloat routines to convert to and from a string. A copy of the output follows the code.

program FileStreamDemo;
uses
  SysUtils, Classes;
var
  fs: TFileStream;
  MyChar1: char = 'a';
  MyString1: string = 'test';
  MyByte1: byte = 254;
  MyCardinal1: Cardinal = 42;
  MyInt1: integer = -42;
  MyQWord1: QWord = 123456789123;
  MyInt64_1: Int64 = -123456789123;

  MyReal1: real = 3.142;

  MyChar2: char;
  MyString2: string;
  MyByte2: byte;
  MyCardinal2: Cardinal;
  MyInt2: integer;
  MyQWord2: QWord;
  MyInt64_2: int64;
  strMyReal: string;
  MyReal2: real;

begin
  fs := TFileStream.Create('test.dat', fmCreate);
  fs.WriteAnsiString(MyChar1);
  fs.WriteAnsiString(MyString1);
  fs.WriteByte(MyByte1);
  fs.WriteDWord(MyCardinal1);
  fs.WriteDWord(MyInt1);
  fs.WriteQWord(MyQWord1);
  fs.WriteQWord(MyInt64_1);
  fs.WriteAnsiString(FloatToStr(MyReal1));
  fs.Free;
  // Read the created file.
  fs := TFileStream.Create('test.dat', fmOpenRead);
  MyChar2 := fs.ReadAnsiString [1];
  MyString2 := fs.ReadAnsiString;
  MyByte2 := fs.ReadByte;
  MyCardinal2 := fs.ReadDWord;
  MyInt2 := fs.ReadDWord;
  MyQWord2 := fs.ReadQWord;
  MyInt64_2 := fs.ReadQWord;
  strMyReal := fs.ReadAnsiString;
  MyReal2 := StrToFloat(strMyReal);
  // Output the original data together with that saved to then read from file.
  writeln('MyChar1: ', MyChar1, ' MyChar2: ', MyChar2);
  writeln('MyString1: ', MyString1, ' MyString2: ', MyString2);
  writeln('MyByte1: ', MyByte1, ' MyByte2: ', MyByte2);
  writeln('MyCardinal1: ', MyCardinal1, ' MyCardinal2: ', MyCardinal2);
  writeln('MyInt1: ', MyInt1, ' MyInt2: ', MyInt2);
  writeln('MyQWord1: ', MyQWord1, ' MyQWord2: ', MyQword2);
  writeln('MyInt64_1: ', MyInt64_1, ' MyInt64_2: ', MyInt64_2);
  writeln('MyReal1: ', MyReal1 : 4 : 3, ' MyReal2: ', MyReal2 : 4 : 3);
  fs.Free;
  readln;
end.

Output:

MyChar1: a MyChar2: a
MyString1: test MyString2: test
MyByte1: 254 MyByte2: 254
MyCardinal1: 42 MyCardinal2: 42
MyInt1: -42 MyInt2: -42
MyQWord1: 123456789123 MyQWord2: 123456789123
MyInt64_1: -123456789123 MyInt64_2: -123456789123
MyReal1: 3.142 MyReal2: 3.142

Using TWriter and TReader

TWriter and TReader are intended for streaming components but you can use them (in conjunction with TFileStream) to write and read binary files as shown in this example. The output follows the code.

program WriterReaderDemo;

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes;
var
  FS : TFileStream;
  Writer : TWriter;
  Reader : TReader;
  MyChar1: Char = 'a';
  MyString1 : String   = 'test';
  MyDouble1: Double = 12.345;
  MyInt1: integer = 42;
  MyInt64_1: Int64 = 123456789123;
  MyChar2: char;
  MyString2: string;
  MyDouble2: Double;
  MyInt2: integer;
  myInt64_2: int64;

begin
  FS := TFileStream.Create('test.dat', fmCreate);
  Writer := TWriter.Create(FS, 1024); // Buffer size 1024
  Writer.WriteChar(MyChar1);
  Writer.WriteString(MyString1);
  Writer.WriteInteger(MyInt1);
  Writer.WriteInteger(MyInt64_1);
  Writer.WriteFloat(MyDouble1);
  Writer.Free;
  FS.Free;
  // Read the created file
  FS := TFileStream.Create('test.dat', fmOpenRead);
  Reader := TReader.Create(FS, 1024);
  MyChar2 := Reader.ReadChar;
  MyString2 := Reader.ReadString;
  MyInt2 := Reader.ReadInteger;
  MyInt64_2 := Reader.ReadInt64;
  MyDouble2 := Reader.ReadFloat;
  // Output data
  writeln('MyString1: ', MyString1, ' MyString2: ', MyString2);
  writeln('MyChar1: ', MyChar1, ' MyChar2: ', MyChar2);
  writeln('MyInt1: ', MyInt1, ' MyInt2: ', MyInt2);
  writeln('MyInt64_1: ', MyInt64_1, ' MyInt64_2: ', MyInt64_2);
  writeln('MyDouble1: ', MyDouble1 : 6: 3, ' MyDouble2: ', MyDouble2 : 6: 3);
  Reader.Free;
  FS.Free;
  readln;
end.

Output:

MyString1: test MyString2: test
MyChar1: a MyChar2: a
MyInt1: 42 MyInt2: 42
MyInt64_1: 123456789123 MyInt64_2: 123456789123
MyDouble1: 12.345 MyDouble2: 12.345
Programming - a skill for life!

Demonstrations of TStringList, TFileString, TQueue and TRegExp and drawing on a canvas