Serial and Sequential File Processing

A sequential file is one where the items are stored in an order determined by a key field. In the case of a file containing discrete data items such as strings or numbers then the order would be alphabetic or numerical. In the case of a file of records with more than one field the file might be sorted on any one or more of them, for example by ID (primary key) or by any other suitable field.

Proceeding from an example, we define a record type and file format as follows:

type
Tperson=record
 name:string[20];
 address:string[20];
 dateofbirth:TDateTime;
end;

Tpersonfile=file of TPerson;

And some variables:

var
 Form1: TForm1;
 person:TPerson;
 personfile:TPersonfile;

Serial Files

To begin with we will create a serial file, that is one where the records are held and accessed in sequence but where they are not sorted on any key field and the order is random.

We set up a form with some edit controls for text entry and a TDateTimePicker for input, some buttons and a listbox for output:

Creating a New File

This routine creates a new file, overwriting any earlier copies.

procedure TForm1.NewButtonClick(Sender: TObject);
begin
 if MessageDlg('Do you want to overwrite the file?', mtConfirmation, [mbYes, mbNo], 0) = mrYes
 then
 begin
  assignfile(personfile,'persons.dat');
  rewrite(personfile);
  closefile(personfile);
 end;
end;

The MessageDlg is used to allow the user to confirm that they want to overwrite the file and thus destroy its contents. You must make sure that the persons.dat file is in the same directory as the program code (or extend the path). Use Notepad to make an empty file and save it as 'persons.dat'.

Improved code using try:

if MessageDlg('Do you want to overwrite the file?', mtConfirmation, [mbYes, mbNo], 0) = mrYes
then
begin
try
assignfile (personfile,'persons.dat');
rewrite (personfile);
end;
finally
CloseFile(personfile);
end;
end;

Writing A Single Record

The first version of the code for the save button writes a single record into the file. The code shown below will write a record at the end of the file:

procedure TForm1.SaveButtonClick(Sender: TObject);
begin
 assignfile(personfile,'persons.dat');
//change file name & path to suit
 reset(personfile);
 with person do
 begin
  name:=edit1.Text;
  address:=edit2.text;
  dateofbirth:=datetimepicker1.Date;
 end;
 seek(personfile,filesize(personfile)); 
//find end of file and
 write(personfile,person); 
//add new record
end;

Notice the use of the seek procedure to find the end of the file before we write a new record into it.

Improved code using try:

begin
 try
assignfile(personfile,'persons.dat');
//change file name & path to suit
 reset(personfile);
 with person do
 begin
  name:=edit1.Text;
  address:=edit2.text;
  dateofbirth:=datetimepicker1.Date;
 end;
 seek(personfile,filesize(personfile)); 
//find end of file and
 write(personfile,person); 
//add new record
end; //try
finally
closefile(personfile);
end;

Displaying the File

procedure TForm1.DisplayButtonClick(Sender: TObject);
var
 lbstring:string;
begin
 listbox1.Clear;
 assignfile(personfile,'persons.dat');
 //change file name & path to suit
 reset(personfile);
 while not eof (personfile) do
 begin
  read(personfile,person);
  lbstring:=person.name + ' ' + person.address + ' ' + datetostr(person.dateofbirth);
  listbox1.Items.Add(lbstring);
 end;
end;

This is unsophisticated but effective for our purposes here.

Sequential Files

To create a sequential file we must place each new item in the correct location within the file. Each time a new record is added to the file we must make sure that it is added at the correct place so that the sequence is maintained. To do this we use two files, the old 'master' file and a new copy that will include the added record in the correct place.

The code to add a new record in the correct place to maintain sequence is now more complex:

procedure TForm1.SaveButtonClick(Sender: TObject);
var
 newpersonfile:Tpersonfile;  
//could add these to interface declarations as with personfile
 newpersonrec, filepersonrec:TPerson;
 inserted:Boolean;
begin
 inserted:=false;
 assignfile(personfile,'persons.dat');
 //change file name & path to suit
 reset(personfile);
 assignfile(newpersonfile,'newpersons.dat');
 //change file name & path to suit
 rewrite(newpersonfile);
 with newpersonrec do
 begin
  name:=edit1.Text;
  address:=edit2.text;
  dateofbirth:=datetimepicker1.Date;
 end;
 if eof(personfile) then write(newpersonfile,newpersonrec);
//new file
 while not eof (personfile) do
 begin
  read(personfile, filepersonrec);
  if (newpersonrec.name < filepersonrec.name) and (not inserted) then
  begin
   write(newpersonfile, newpersonrec);
//add new record
   write(newpersonfile, filepersonrec); 
//add file record
   inserted:=true;
  end
  else
   write(newpersonfile, filepersonrec);
//not place to insert new record so write file record
  if (eof(personfile)) and (not inserted) then write(newpersonfile,newpersonrec);
//where new items > last in file
 end;
//while
 closefile(personfile);
 closefile(newpersonfile);
 assignfile(personfile,'persons.dat'); 
//copy records from new file.  Change file name & path to suit
 rewrite(personfile);                          
//to old file
 assignfile(newpersonfile,'newpersons.dat');
 //change file name & path to suit
 reset(newpersonfile);
 while not eof(newpersonfile) do
 begin
  read(newpersonfile, filepersonrec);
  write(personfile,filepersonrec);
 end;
 closefile(personfile);
 closefile(newpersonfile);
 assignfile(newpersonfile,'newpersons.dat');
 //change file name & path to suit
 rewrite(newpersonfile); 
//empty file for next time
 closefile(newpersonfile);
end;

Alternative code:

procedure TForm1.SaveButtonClick(Sender: TObject);
var
 person, newperson:TPerson;
 personfile, personfiletemp:TPersonfile;
 added:Boolean;
begin
 added:=false;
 assignfile(personfile,'persons.dat');
 reset(personfile);
 assignfile(personfiletemp,'personstemp.dat');
 rewrite(personfiletemp);
 with newperson do
 begin
  name:=edit1.Text;
  address:=edit2.text;
  dateofbirth:=datetimepicker1.Date;
 end;
 while not eof (personfile) do
 begin
  read(personfile,person);
  if newperson.name > person.name then
   write (personfiletemp,person)
 else
  if (newperson.name <= person.name) and (added=false) then
   begin
    write(personfiletemp,newperson);
    write (personfiletemp,person);
    added:=true;
   end
  else
   if (newperson.name <= person.name) and (added=true) then
    write (personfiletemp,person)
 end;
//while
 if not added then write(personfiletemp,newperson);
 closefile(personfile);
 closefile(personfiletemp);
 assignfile(personfiletemp,'personstemp.dat');
 reset(personfiletemp);
 assignfile(personfile,'persons.dat');
 rewrite(personfile);
 while not eof(personfiletemp) do
 begin
  read(personfiletemp,person);
  write(personfile, person);
 end;
 closefile(personfile);
 closefile(personfiletemp);
end;

The code uses a Boolean value to determine whether the new record has been added to the file. When a new record is read from the existing file there are multiple conditions to test:

We could also read the entire file into memory and sort it with the new record included. The process using a sort algorithm looks like this:

procedure TForm1.SaveButtonClick(Sender: TObject);
var
 person, newperson:TPerson;
 personfile, personfiletemp:TPersonfile;
 personarray:array[1..100] of TPerson;
 i,j,k,m:integer;
 tempPerson:TPerson;
begin
 assignfile(personfile,'persons.dat');
 reset(personfile);
 assignfile(personfiletemp,'personstemp.dat');
 rewrite(personfiletemp);
 while not eof (personfile) do
 begin
  read(personfile,person);
  write(personfiletemp,person);
 end;
 with newperson do
 begin
  name:=edit1.Text;
  address:=edit2.text;
  dateofbirth:=datetimepicker1.Date;
  write(personfiletemp,newperson);
 end;
 closefile(personfile);
 closefile(personfiletemp);
 //read temp file into array
 assignfile(personfiletemp,'personstemp.dat');
 reset(personfiletemp);
 i:=0;
 while not eof(personfiletemp) do
 begin
  inc(i);
  read(personfiletemp,personarray[i]);
 end;
 closefile(personfiletemp);
 //bubble sort array
 for j:= 1 to i-1 do
  for k:= j+1 to i do
   if personarray[j].name > personarray[k].name then
   begin
    tempPerson:=personarray[j];
    personarray[j]:=personarray[k];
    personarray[k]:=tempPerson;
   end;
  //write temp file to master
 assignfile(personfile,'persons.dat');
 rewrite(personfile);
 for m :=1 to i do
 begin
  showmessage(inttostr(m));
  write (personfile, personarray[m]);
 end;
 closefile(personfile);
end;

This uses an array to hold the file in memory while it is sorted. The issue here is how large to make the array. Again, the same display procedure will do the job.

As well as adding records to a sequential file we also need to be able to delete them and amend them.

Deleting Records

Deleting a record is the reverse of adding a new one. We need to identify the record to be deleted and then skip over it as we write records from the old file to the new one. This turns out to be less complex than the insertion routine because we simply need to compare the current record from the file with the item to be deleted and, if they are not the same, write the record to the new file; if they are the same then the current record will not be written and so will be deleted.

procedure TForm1.deleteClick(Sender: TObject);
var
 person:TPerson;
 personfile, personfiletemp:TPersonfile;
begin
 assignfile(personfile,'persons.dat');
 reset(personfile);
 assignfile(personfiletemp,'personstemp.dat');
 rewrite(personfiletemp);
 if not (namebox.text='') then
 begin
  while not eof (personfile) do
  begin
   read(personfile, person);
   if not (person.name = namebox.Text) then
   write(personfiletemp, person);
  end;
 end
 else
  showmessage('You must enter a name to delete');
 closefile(personfile);
 closefile(personfiletemp);
 assignfile(personfiletemp,'personstemp.dat');
 reset(personfiletemp);
 assignfile(personfile,'persons.dat');
 rewrite(personfile);
 while not eof(personfiletemp) do
 begin
  read(personfiletemp,person);
  write(personfile, person);
 end;
 closefile(personfile);
 closefile(personfiletemp);
end;

Amending Records

A third major operation on file data involves changing fields within a record, as in the case of a balance after new transactions or where an address is changed. In the following code the amendments to a record have been placed in appropriate text boxes, the file is searched for a matching key field and the corresponding record is updated before copying it to a temporary file.

procedure TForm1.amendClick(Sender: TObject);
var
 person, amendperson:TPerson;
 personfile, personfiletemp:TPersonfile;
begin
 assignfile(personfile,'persons.dat');
 reset(personfile);
 assignfile(personfiletemp,'personstemp.dat');
 rewrite(personfiletemp);
 if not (namebox.text='') then
 begin
  while not eof(personfile) do
  begin
   read(personfile, person);
   if person.name=namebox.Text then
   begin
    with amendperson do
    begin
     name:=namebox.text;
     address:=addressbox.text;
     dateofbirth:=datetimepicker1.Date;
    end;
    write(personfiletemp, amendperson);
   end
   else
    write(personfiletemp, person);
  end;
 end
 else
  showmessage('You must enter a name to amend');
 closefile(personfile);
 closefile(personfiletemp);
 assignfile(personfiletemp,'personstemp.dat');
 reset(personfiletemp);
 assignfile(personfile,'persons.dat');
 rewrite(personfile);
 while not eof(personfiletemp) do
 begin
  read(personfiletemp,person);
  write(personfile, person);
 end;
 closefile(personfile);
 closefile(personfiletemp);
end;

Rather than implement customised file routines, including insert, delete, merge and modify, it is now more common to put data inside a database and to access it using technologies such as ADO.

Back to Tutorial