Amending a File: Add, Delete, Amend a Record

program amend_pupils;
type pupil_record = record
          name : string[20];
          form : string[3];
          year_of_entry: integer;
        end;
        pupil_array = array of pupil_record;
        pupil_data = file of pupil_record;

var   pupils : pupil_array;
        pupil_file : pupil_data;
        x : char;
        choice, array_length : integer;

procedure sort_array;
var i, j : integer;
      temp : pupil_record;
begin
  for i := 0 to array_length -2 do
    for j := i + 1 to  array_length -1 do
      if pupils[i].name > pupils[j].name then
        begin
          temp := pupils[i];
          pupils[i] := pupils[j];
          pupils[j] := temp;
        end;
end;

procedure retrieve_data;
begin
  array_length := 1;
  pupils := nil;
  SetLength (pupils, array_length);
  assign (pupil_file, 'pupils.dat');
  reset (pupil_file);
  while not eof (pupil_file) do
     begin
       read (pupil_file, pupils[array_length-1]);
       inc (array_length);
    end;
  close (pupil_file);
  dec (array_length); {array_length was incremented in loop so now we decrement it}
end;

procedure save_data;
var i: integer;
begin
  sort_array;
  assign (pupil_file, 'pupils.dat');
  rewrite (pupil_file);
  for i:= 0 to array_length - 1 do
    write (pupil_file, pupils[i - 1]);
  close (pupil_file);
end;

procedure show_data;
var i : integer;
begin
  retrieve_data;
  for i:=0 to array_length -1 do
   with pupils[i] do
     writeln ('Name: ', name, ' Form: ', form, ' Year of entry: ', year_of_entry);
end;

procedure find_data (var name_to_find: string; var found: Boolean);
var i : integer;
      found : Boolean;
begin
  found := false;
  writeln ('Enter name of student, surname followed by first name eg Smith, Tom.');
  readln (name_to_find);
  retrieve_data;
  for i := 0 to array_length - 1 do
    if pupils[i].name = name_to_find then
      begin
        writeln ('Student found.');
        writeln ('Name: ', pupils[i].name);
        writeln ('Form: ', pupils[i].form);
        writeln ('Year of entry: ', pupils[i].year_of_entry);
        found := true;
      end;
    if not found then writeln (name_to_find, ' not found');
end;

procedure get_new_record (var new_record: pupil_record);
begin
 with new_record do
  begin
   writeln ('Enter name:');
   readln (name);
   writeln ('Enter form:');
   readln (form);
   writeln ('Enter year of entry:');
   readln (year_of_entry);
  end;
end;

procedure add_data ;
var nr : pupil_record;
begin
  retrieve_data;
  get_new_record (nr);
  array_length := array_length + 1;
  pupils(array_length - 1) := nr;
  save_data;
end;

procedure remove_data;
var name_to_delete : string[20];
      i, j : integer;
begin
  writeln ('Enter name of pupil to delete from file');
  readln (name_to_delete);
  retrieve_data;
  i := 0;
  while i < array_length do
    begin
      if pupils[i].name = name_to_delete 
        then
          for j := i to array_length - 1 do
            pupils[j] := pupils[j + 1];
      inc(i);
    end;
  array_length := array_length - 1;
  save_data;
end;

procedure amend_data;
var name_to_amend : string[20];
      i, j : integer;
      t : char;
begin
  writeln ('Enter name of pupil to amend')
  readln (name_to_amend);
  retrieve_data;
  i := 0;
  while i < array_length do
    if pupils[i].name = name_to_amend 
      then
        begin
          writeln ('Enter field to amend, N)ame, F)orm, Y)ear of Entry');
          readln (t);
          case t of
            'N' : begin
                     writeln ('Enter amended name');
                     readln (pupils[i].name);
                   end;
            'F' : begin
                     writeln ('Enter amended form');
                     readln (pupils[i].form);
                   end;
            'Y' : begin
                     writeln ('Enter amended year of entry');
                     readln (pupils[i].year_of_entry);
                   end;
          end; {case}
          i := array_length; {finish loop when name found}
        end {if}
        else inc (i); {if name not found inc (i)}
  save_data;
end;

procedure create_file;
var nr : pupil_record;
begin
  get_new_record (nr);
  array_length := 1;
  setlength (pupils, array_length);
  assign (pupil_file, 'pupils.dat');
  rewrite (pupil_file);
  write (pupil_file, nr);
  close (pupil_file);
end;

begin
  repeat
  writeln ('Enter choice from these options:');
  repeat
    writeln ('1. Show data');
    writeln ('2. Find a record from a name');
    writeln ('3. Add a new record to the file');
    writeln ('4. Remove a record from the file');
    writeln ('5. Amend a record in the file');
    writeln ('6. Quit');
    readln (choice);
    if not (choice in [1..6]) then writeln ('Invalid character, try again');
  until (choice in [0..6]);
  case choice of 
    1: show_data;
    2: find_data;
    3: add_data;
    4: remove_data;
    5: amend_data;
    6: writeln;
  end;
  until choice = 6;
  readln (x);
end.

In this next version of the program we dispense with the read_data procedure and instead use add_data, which adds one new record to the file. We also introduce dynamic arrays, which are able to expand as the situation requires. 

We now use a procedure to add records to the data file one at a time. We can use a one-off procedure, create_file, to create a file with one record, otherwise there may not be a file called 'pupils.dat' on the disc. Run this routine by adding an option 0 to 'create_file', or 'retrieve_data' to open an existing file. 

To add a record we open the file and read the records into an array. This array is dynamic and expands to hold the records we input from the file. Dynamic arrays are indexed from 0 (unlike static arrays, which are indexed from 1). We maintain a value for the length of the array and generally count from 0 to this length property minus 1 (the array index runs from 0 to the length - 1). When the length of the array is 1 the index of the first item is [0] so we use length - 1. We must initialise a dynamic array with SetLength (file, length) before we can use it for the first time, but after that it grows without SetLength as we add new records to it. We then get the new record data, expand the array by one and write the enlarged array to the file.

To delete a record we again read the records into the dynamic array. We then compare the search name with the names in the records. If we find a match we write over the current record and subsequent ones from the rest of the array - array[3] becomes array[4], etc. We then reduce the size of the array and save the amended file.

To amend a record we find it in the array, replace the existing data with the amended data and then save the array into the file. 

Each time we save the array we sort it first.

We leave in the facilities to show the contents of the file.

Back to questions