Programming Taskbook

Russian

E-mail:

Password:

User registration   Restore password

1000 training tasks on programming

©  M. E. Abramyan, 1998–2011

 

Examples | Pascal | File processing

PrevNext


File processing

Solutions of tasks connected with processing of binary files with numeric data and also string files and text files are described on this page.

Binary file with numeric data: File48

This section contains description of solving the following task:

File48°. Three files of integers called SA, SB, SC and a string SD are given. All given files are of the same size. Create a new file called SD; this file must contain triples of components of the given files as follows: A1B1C1, A2B2C2, ... .

Creating a template and acquaintance with the task

To create a template of the required task one should use PT4Load tool:

{$D+,I+,L+,Q+,R+,S+}
program File48;
uses PT4;

begin
  Task('File48');
end.

When the program is launched you will see the Programming Taskbook window:

The first line of the input data panel contains four file names: SA, SB, and SC for input files, SD for an output file. The next three lines of the input data panel displays components of the input files. File components are light-cyan colored to distinguish them from standard input-output data and comments. With mouse or keyboard you can scroll the file components .

All input files are created with new name and data for each test running of the program. When the program finishes all files are removed automatically from the working directory.

The running of our program is considered as acquaintance running because the program does not perform input-output operations. In the panel of results the "Example of right solution" tab is active; this tab displays components that should be saved in the output file.

Initial data input

Before solving the task it is necessary to input file names and assign these files to the corresponding file variables. We shall use array to store file variables:

var
  i: integer;
  s: string;
  f: array[1..4] of file of integer;
begin
  Task('File48');
  for i := 1 to 3 do
  begin
    GetS(s);
    Assign(f[i], s);
  end;
end.

Because we input only three file names, the next program running will lead to the error message "Some required data are not input.".

To correct this error it is enough to replace 3 by 4 in the for statement. Now data input is performed correctly, but the program does not create an output file. Therefore we shall see the following message: "Output file is not found".

Run-time errors in the program

To open input files we add the Reset procedure to the loop in our program:

var
  i: integer;
  s: string;
  f: array[1..4] of file of integer;
begin
  Task('File48');
  for i := 1 to 4 do
  begin
    GetS(s);
    Assign(f[i], s);
    Reset(f[i]);
  end;
end.

When the program will be started we shall see the following error message: "Error EInOutError: File not found" . This message means that the run-time error occurs. Any run-time error in Delphi Pascal throws an exception; the message contain the name of exception (EInOutError) and its brief description.

Creating an empty output file

To avoid the run-time error you should open a non-existing file by the Rewrite procedure. Furthermore, you should close all files at the end of the program:

var
  i: integer;
  s: string;
  f: array[1..4] of file of integer;
begin
  Task('File48');
  for i := 1 to 4 do
  begin
    GetS(s);
    Assign(f[i], s);
    if i < 4 then Reset(f[i])
    else Rewrite(f[i]);
  end;
  { * }
  for i := 1 to 4 do
    Close(f[i]);
end.

The {*} comment marks the program position, where we can execute input-output file operations: files are already opened by the Reset or Rewrite procedures and are not closed by the Close procedure.

Running of this program provides creation of an output file. But this file will be empty, that is, will contain no elements. Therefore we shall see the error message "Wrong solution", and the output data panel will contain the following text:

EOF:

This text (EOF—End Of File) means that the output file exists but contains no elements.

Using of wrong type for file components

We did not use file input-output operations so far. Therefore we could specify any type for file components (for example, real type), and the result of the program running would be the same.

But if the program contains file input-output operations then it is important to specify the type of file components correctly, otherwise "strange" errors will occurs during the program running. Let's model this situation in our program. For this purpose we replace the "integer" specifier in the declaration of the f array by the "real" one, add the declaration of a real-valued variable named a, and replace the { * } comment by the following statements:

for i := 1 to 3 do
begin
  read(f[i], a);
  write(f[4], a);
end;

The given statements provide reading one component from each input file and writing these components to the output file (in the required order). Note that we have specified the file types incorrectly, but the program will be compiled successfully, and it will execute without run-time errors.

The result of the program execution will be unexpected: the output file will contain six components, that is, two components of each input file. It can be explained as follows. In our program the file elements are assumed to be real numbers (of size 8 bytes). But in fact the input files contains integer components (of size 4 bytes). Therefore reading and writing of one "real-valued" component leads to reading/writing of two integer components.

Thus, we see that the errors connected with the incorrect file types are not detected by compiler and do not usually lead to the run-time errors, but often lead to "strange" results.

After replacing the "real" specifier in declarations by the "integer" one our program will work quite "clearly": the output file will contain three components, that is, one initial component of each input file.

Correct solution, its testing and browsing results

At last, let's present a correct algorithm for the File48 task:

var
  i: integer;
  s: string;
  f: array[1..4] of file of integer;
  a: integer;
begin
  Task('File48');
  for i := 1 to 4 do
  begin
    GetS(s);
    Assign(f[i], s);
    if i < 4 then Reset(f[i])
    else Rewrite(f[i]);
  end;
  while not Eof(f[1]) do
    for i := 1 to 3 do
    begin
      Read(f[i], a);
      Write(f[4], a);
    end;
  for i := 1 to 4 do
    Close(f[i]);
end.

This algorithm contains the "while" loop that provides reading all components from the input files (recall that all input files are of the same size). After running the program we shall see the message "Right solution. The test 1 of 5", and after 5 test runnings we shall receive the message "The task is solved!".

Using the PT4Results tool we can browse information about all test runnings of our program:

File48     d03/05 17:24 Acquaintance with the task.
File48     d03/05 17:27 Some required data are not input.
File48     d03/05 17:29 Output file is not found.
File48     d03/05 17:32 Error EInOutError.
File48     d03/05 17:38 Wrong solution.--3
File48     d03/05 17:41 The task is solved!

String binary files and text files: File67, Text21

In this section we shall discuss some features of processing of string files (i.e., binary typed files whose components are strings) and text files.

String files

Let's consider the File67 task as an example of task with string file processing:

File67°. A file of strings is given. The file contains dates in the "day/month/year" format, the "day" and "month" fields contain two digits, the "year" field contains four digits (for example, "16/04/2001"). Create two new files and write integer values of days and months for each date from the given file to the first and second resulting file respectively (in the same order).

To process the string files in the Delphi system it is necessary to use file variables of the file of ShortString type. The variables used for file input-output operations must have ShortString type too. The ShortString type refers to "short" Pascal strings, which may contain no more than 255 symbols. Note that by default the Delphi compiler interprets the "string" type as the AnsiString type that can store very long strings (up to 2 GB length). Pascal string types can be mixed in assignments and expressions; the compiler automatically performs required conversions. But a parameter of the GetS procedure must be of the AnsiString type only (a parameter of the PutS procedure may be of any string type).

Taking into account all features mentioned above we can solve the File67 task as follows:

program File67;
uses PT4, SysUtils;
var
  f: file of ShortString;
  f1, f2: file of integer;
  s: string;
  ss: ShortString;
  a: integer;
begin
  Task('File67');
  GetS(s);
  Assign(f, s);
  Reset(f);
  GetS(s);
  Assign(f1, s);
  Rewrite(f1);
  GetS(s);
  Assign(f2, s);
  Rewrite(f2);
  while not Eof(f) do
  begin
    Read(f, ss);
    a := StrToInt(Copy(ss, 1, 2));
    Write(f1, a);
    a := StrToInt(Copy(ss, 4, 2));
    Write(f2, a);
  end;
  Close(f);
  Close(f1);
  Close(f2);
end.

To convert a string to an integer we have used the StrToInt function. This function is declared in the SysUtils standard unit, therefore this unit has been included in the uses clause.

Note that it is necessary to use a variable for writing data to resulting files because parameters of the Write procedure for binary files are passed by reference.

Text files

Let's consider the Text21 task as an example of task with text file processing:

Text21°. Given a text file that contains more than three lines, remove its last three lines.

Text files, unlike binary files, cannot be open for reading and writing simultaneously, therefore it is necessary to use an temporary file for text file changing: the required output data should be written to the temporary file, after that the initial file should be removed and the temporary file name should be changed to the initial file name. Lines of the text file are of various length, therefore it is necessary to read all lines to determine the amount of lines in the text file. The FileSize and FilePos functions and the Seek procedure are unavailable for the text files. Parameters of the input-output procedures for text files may be of any string type.

Considering all features mentioned above we can solve the Text21 task as follows:

program Text21;
uses PT4;
var
  name, s: string;
  f1, f2: text;
  n, i: integer;
begin
  Task('Text21');
  GetS(name);
  Assign(f1, name);
  Reset(f1);
  Assign(f2, '$T21$.tmp');
  Rewrite(f2);
  n := 0;
  while not Eof(f1) do
  begin
    Readln(f1, s);
    Inc(n);
  end;
  Reset(f1);
  for i := 1 to n - 3 do
  begin
    Readln(f1, s);
    Writeln(f2, s);
  end;
  Close(f1);
  Close(f2);
  Erase(f1);
  Rename(f2, name);
end.

This algorithm is inefficient because it requires to read the initial file twice: the first time to determine the amount of file lines, the second time to create an temporary file that will contain all lines of the initial file except three last ones.

The Text21 task can be solved using only one reading of the initial file. In this solution we'll take into account the following consideration: a text line should be written to an temporary file if at least three lines follow this line in the file. This way of solution does not requires to determine the amount of the text lines. To store strings, which have been read from the input file but still have not been written to the temporary file, we shall use an array of three elements.

We obtain the second, one-pass algorithm of the Text23 solution:

program Text21a;
uses PT4;
var
  name: string;
  f1, f2: text;
  s: array[0..2] of string;
  n, i: integer;
begin
  Task('Text21');
  GetS(name);
  Assign(f1, name);
  Reset(f1);
  Assign(f2, '$T21$.tmp');
  Rewrite(f2);
  for i := 0 to 2 do
    Readln(f1, s[i]);
  n := 0;
  while not Eof(f1) do
  begin
    Writeln(f2, s[n]);
    Readln(f1, s[n]);
    n := (n + 1) mod 3;
  end;
  Close(f1);
  Close(f2);
  Erase(f1);
  Rename(f2, name);
end.

PrevNext

 

 

Designed by
M. E. Abramyan and V. N. Braguilevsky

Last revised:
04.06.2011