Chapter 13 Exercises: Files and I/O
Part A: Comprehension (Short Answer)
Exercise 13.1 — Explain the difference between Rewrite, Reset, and Append. What happens if you call Rewrite on a file that already exists? What happens if you call Reset on a file that does not exist?
Exercise 13.2 — Why must you use string[N] (short strings) rather than string (AnsiString) in records that will be stored in typed files? What would happen if you used a dynamic string?
Exercise 13.3 — What is the difference between Eof(F) and Eoln(F)? In what type of file does Eoln make sense, and in what type does it not?
Exercise 13.4 — After calling Read(F, Student) on a typed file, where is the file pointer? Why is this important when you want to update a record in place?
Exercise 13.5 — Explain why you must call IOResult immediately after the I/O operation you want to check. What happens if you call WriteLn between the I/O operation and the IOResult call?
Exercise 13.6 — What does the Truncate(F) procedure do? Can it be used with text files?
Exercise 13.7 — Compare Erase(F) with DeleteFile(FileName) from SysUtils. What are the advantages of each approach?
Part B: Tracing and Prediction
Exercise 13.8 — Predict the contents of output.txt after this code runs:
var
F: TextFile;
begin
AssignFile(F, 'output.txt');
Rewrite(F);
WriteLn(F, 'Alpha');
WriteLn(F, 'Beta');
CloseFile(F);
AssignFile(F, 'output.txt');
Rewrite(F);
WriteLn(F, 'Gamma');
CloseFile(F);
AssignFile(F, 'output.txt');
Append(F);
WriteLn(F, 'Delta');
CloseFile(F);
end.
Exercise 13.9 — What is the value of Pos after each Seek and Read call?
type
TRec = record
Value: Integer;
end;
var
F: file of TRec;
R: TRec;
Pos: Integer;
begin
AssignFile(F, 'data.dat');
Rewrite(F);
R.Value := 10; Write(F, R);
R.Value := 20; Write(F, R);
R.Value := 30; Write(F, R);
R.Value := 40; Write(F, R);
R.Value := 50; Write(F, R);
CloseFile(F);
AssignFile(F, 'data.dat');
Reset(F);
Pos := FilePos(F); { Pos = ? }
Seek(F, 3);
Pos := FilePos(F); { Pos = ? }
Read(F, R);
Pos := FilePos(F); { Pos = ? }
WriteLn(R.Value); { Output = ? }
CloseFile(F);
end.
Exercise 13.10 — What does this code print? Trace through carefully.
var
F: TextFile;
Line: string;
Count: Integer;
begin
AssignFile(F, 'test.txt');
Rewrite(F);
WriteLn(F, 'one');
WriteLn(F, 'two');
WriteLn(F, 'three');
CloseFile(F);
AssignFile(F, 'test.txt');
Reset(F);
Count := 0;
while not Eof(F) do
begin
ReadLn(F, Line);
Inc(Count);
end;
CloseFile(F);
WriteLn('Lines: ', Count);
end.
Exercise 13.11 — This code has a bug. Find it and explain why it fails:
var
F: TextFile;
IOCode: Integer;
begin
AssignFile(F, 'missing.txt');
{$I-}
Reset(F);
WriteLn('Attempting to open file...');
IOCode := IOResult;
{$I+}
if IOCode = 0 then
WriteLn('File opened successfully!')
else
WriteLn('Error code: ', IOCode);
end.
Part C: Short Programs
Exercise 13.12 — Write a program that creates a text file called numbers.txt containing the integers 1 through 100, one per line. Then read the file back and compute the sum.
Exercise 13.13 — Write a program that reads a text file specified by the user and reports: - The number of lines - The number of words (whitespace-separated tokens) - The number of characters (excluding newlines)
This is a simplified version of the Unix wc command.
Exercise 13.14 — Write a program that reads a text file and creates a new file with all lines reversed. If the input contains "Hello\nWorld\nPascal", the output should contain "Pascal\nWorld\nHello". (Hint: read all lines into an array first.)
Exercise 13.15 — Write a program that uses a typed file (file of Integer) to store 20 random integers. Then read the file back, find the minimum and maximum, and display them.
Exercise 13.16 — Write a procedure AppendRecord that adds a single TStudent record to the end of an existing typed file. If the file does not exist, create it. Use IOResult for error handling.
Exercise 13.17 — Write a program that copies a file using untyped file I/O with BlockRead and BlockWrite. The source and destination filenames should be entered by the user. Report the number of bytes copied.
Exercise 13.18 — Write a function CountRecords(FileName: string): Integer that opens a typed file of TStudent and returns the number of records it contains, using FileSize. If the file does not exist, return -1.
Exercise 13.19 — Write a program that reads a CSV file with the format Name,Age,City and displays the data in a formatted table:
Name Age City
---- --- ----
Alice Johnson 28 Seattle
Bob Smith 34 Portland
Part D: Analytical and Design
Exercise 13.20 — A student writes this code to "append" to a typed file:
AssignFile(F, 'records.dat');
Rewrite(F);
Seek(F, FileSize(F));
Write(F, NewRecord);
CloseFile(F);
Explain why this does not work as intended. What does Rewrite do to the existing data? Write the corrected version.
Exercise 13.21 — Design a simple inventory system for a small store. Define a TProduct record with fields for name, price, quantity, and a product ID. Write procedures to:
- Add a new product
- Display all products
- Update the quantity of a product by its ID (using random access)
- Save and load the inventory using a typed file
Write the record declaration and procedure signatures. You do not need to implement the full menu system, but implement at least the save, load, and update-by-ID procedures.
Exercise 13.22 — Compare these two approaches to storing a list of 1000 student names:
- Approach A: A text file with one name per line
- Approach B: A typed file of
record Name: string[50]; end
Analyze each approach in terms of: (a) disk space used, (b) speed of reading all records, (c) speed of accessing the 500th record directly, (d) ability to edit with a text editor, (e) ability to store names longer than 50 characters.
Exercise 13.23 — A program stores employee records in a typed file. The original record is:
type
TEmployeeV1 = record
Name: string[40];
Salary: Real;
end;
The developer wants to add an Email: string[60] field. What happens if they change the record definition and try to read the old file with the new record type? Design a migration strategy that reads the old file and creates a new file with the updated record format.
Exercise 13.24 — Write a "file statistics" utility that accepts a filename from the command line and reports: - File size in bytes (use untyped file I/O) - Whether the file appears to be text or binary (heuristic: check if more than 10% of bytes are outside the printable ASCII range 32..126 and common whitespace 9, 10, 13)
Part E: Challenge Problems
Exercise 13.25 — Implement a simple text editor that supports these commands:
- NEW — start a new file
- LOAD filename — load a text file into memory (array of strings)
- LIST — display all lines with line numbers
- INSERT n text — insert a line of text at line number n
- DELETE n — delete line n
- SAVE filename — save to a text file
You will need a dynamic array of lines with insert/delete operations.
Exercise 13.26 — Implement a "high score table" for Crypts of Pascalia. Use a typed file to store the top 10 scores. The record should include the player name, score, and date. When a game ends, check if the player's score qualifies for the table. If so, insert it in the correct sorted position and drop the lowest score if the table is full.
Exercise 13.27 — Write a program that merges two sorted text files of integers (one integer per line) into a third sorted file. The merge should be efficient — read from each file in sequence, comparing values, without loading either file entirely into memory. This is the "merge" step of merge sort applied to files.
Exercise 13.28 — Implement a simple indexed file system. Maintain two files:
- A typed file of TContact records (name, phone, email)
- A separate text file serving as an index: each line contains a name and the record number where that contact is stored
Write procedures to add a contact (append to both files), search by name (scan the index, then Seek to the record), and delete by name (mark as deleted in the data file and remove from the index).
Part M: Metacognitive Reflection
Exercise 13.29 — File I/O introduces a new class of errors that do not exist in pure in-memory programs. List at least five things that can go wrong during file operations that cannot go wrong when working only with variables in memory. How does this change the way you think about error handling?
Exercise 13.30 — Before this chapter, how did you think programs stored data between runs? Has your mental model changed? If you were designing a phone contacts app, which file type would you choose and why?
Exercise 13.31 — The {$I-} / IOResult pattern requires careful discipline — you must check IOResult immediately and cannot perform any other I/O in between. Compare this to exception-based error handling (try...except). Which approach do you find more intuitive? Which is more error-prone? Why might Pascal have originally chosen the IOResult approach over exceptions?