Serial and Sequential Text Files

This note focuses on implementing file storage and retrieval. For basic file opening, reading, writing, and appending, see O.

You can read this note directly if you know strings, lists/tuples, loops, with open(...), and simple functions. The key beginner habit is to remember that a file stores text. When a program reads a file, the fields first arrive as strings. The program must then split, clean, and convert the fields before using them as numbers or keys.

Caption: Serial files store records in arrival order and may require a full scan; sequential files store records in key order, so search can stop early when the current key passes the target.

File State Versus Program State

Variables disappear when the program ends. File contents remain on disk.

StateExample
program statestudent_id = "1001" while the program runs
file statethe line 1001,Aisha,72 stored in a text file

Implementation questions often ask you to move between these two states:

  • read a line from a file into program variables;
  • convert text fields into suitable data types;
  • search records using a key field;
  • write program variables back as a line of text.

A useful beginner pattern is:

file line -> split fields -> convert fields -> process record

and, in the other direction:

program variables -> format as text -> write line to file

File Modes You Must Recognise

The file mode controls what the program is allowed to do and what happens to existing contents.

ModeMeaningWhat happens to existing contents?Common use
"r"readcontents must already existsearch or load records
"w"writeold contents are replacedrewrite a whole file
"a"appendold contents are preservedadd a new serial record at the end

Beginner warning: "w" does not mean “write one more record”. It means “open for writing from the beginning”, so the old file contents are overwritten.

Use with open(...) so that Python closes the file automatically after the block finishes.

def count_lines(path):
    count = 0
    with open(path, "r", encoding="utf-8") as file:
        for line in file:
            count = count + 1
    return count

Records and Key Fields

A text file record is often stored as one line.

1001,Aisha,72
1004,Bo,85
1008,Chen,68

Here:

  • 1001 is the key field;
  • Aisha is a name field;
  • 72 is a mark field.

The key field is the field used to identify or order records. In this example, student_id is the key.

When reading a line, split it into fields and convert numeric fields.

def parse_record(line):
    student_id, name, mark_text = line.strip().split(",")
    return student_id, name, int(mark_text)

Trace:

ExpressionValue
line.strip()"1001,Aisha,72"
.split(",")["1001", "Aisha", "72"]
int(mark_text)72

The .strip() call removes the newline character "\n" at the end of the line. Without it, the last field may contain an extra newline.

This note uses simple comma-separated records for syllabus-level examples. Real CSV files can be more complicated, especially when fields may contain commas inside quoted text.

Serial File

A serial file stores records in the order they are added. This is also called arrival order.

For example, if records are appended in this order:

1004,Bo,85
1001,Aisha,72
1008,Chen,68

then the file keeps that order. It does not automatically sort itself.

Appending to a Serial File

To add a new record to the end of a serial file, use append mode "a".

def append_record(path, student_id, name, mark):
    with open(path, "a", encoding="utf-8") as file:
        file.write(f"{student_id},{name},{mark}\n")

Mini-trace:

Before append:
1001,Aisha,72
 
After append 1004,Bo,85:
1001,Aisha,72
1004,Bo,85

The newline "\n" is important. It keeps each record on a separate line.

Searching a Serial File

Searching a serial file may require checking every line, because the records are not ordered by key.

def find_record(path, target_id):
    with open(path, "r", encoding="utf-8") as file:
        for line in file:
            student_id, name, mark = parse_record(line)
            if student_id == target_id:
                return student_id, name, mark
    return None

Serial search trace for target 1008:

Line readKeyAction
1004,Bo,851004keep searching
1001,Aisha,721001keep searching
1008,Chen,681008return record

If there are records, a serial search may need to inspect up to records.

Code Reading

Code partPurpose
with open(path, "r", encoding="utf-8")open the file for reading
for line in fileread one record line at a time
parse_record(line)convert one line into fields
if student_id == target_idcheck whether this is the wanted record
return Nonereport that the target was not found

Sequential File

A sequential file stores records in order by a key field.

For example, if records are sorted by student_id, the file may look like this:

1001,Aisha,72
1004,Bo,85
1008,Chen,68

The important point is not that the records are stored in a file. The important point is that they are stored in key order.

If records are sorted by student_id, a search can stop early when the current key is greater than the target key.

def find_record_sequential(path, target_id):
    with open(path, "r", encoding="utf-8") as file:
        for line in file:
            student_id, name, mark = parse_record(line)
            if student_id == target_id:
                return student_id, name, mark
            if student_id > target_id:
                return None
    return None

This early stop is only valid if the file is truly sorted by the key.

Sequential search trace for target 1002:

Line readKeyAction
1001,Aisha,721001keep searching
1004,Bo,851004stop; 1002 cannot appear later

Why the early stop works:

The file is sorted by key.
Once the current key has passed the target key,
all later keys must be even larger.
Therefore the target cannot be later in the file.
FeatureSerial fileSequential file
Record orderarrival orderkey-field order
Append new recordsimple: add at endmay break sorted order
Search strategyusually check until found or endmay stop early when key is passed
Main riskslow search for large filesearly stop is wrong if file is not sorted

A sequential file does not mean “the file is read line by line”. Both serial and sequential text files are normally read line by line. The difference is the stored order of the records.

Writing a Sequential File

One simple approach for small syllabus examples is:

  1. read all records;
  2. add the new record;
  3. sort by key;
  4. rewrite the file.
def write_records_sequential(path, records):
    records = sorted(records, key=lambda record: record[0])
    with open(path, "w", encoding="utf-8") as file:
        for student_id, name, mark in records:
            file.write(f"{student_id},{name},{mark}\n")

This approach is suitable for small examples. Very large files need more careful processing because reading all records into memory may not be practical.

Read-Add-Sort-Rewrite Trace

Suppose the file currently stores:

1001,Aisha,72
1008,Chen,68

and the new record is:

1004,Bo,85
StepProgram/file state
read records[('1001', 'Aisha', 72), ('1008', 'Chen', 68)]
add record[('1001', 'Aisha', 72), ('1008', 'Chen', 68), ('1004', 'Bo', 85)]
sort by key[('1001', 'Aisha', 72), ('1004', 'Bo', 85), ('1008', 'Chen', 68)]
rewrite filerecords are written back in key order

The rewrite step uses "w" because the whole file is being replaced by the newly sorted contents.

Reading All Records

The previous function assumes the records are already stored in a list. A helper function can read the file into a list of tuples.

def read_records(path):
    records = []
    with open(path, "r", encoding="utf-8") as file:
        for line in file:
            records.append(parse_record(line))
    return records

Then a simple insertion workflow is:

def insert_record_sequential(path, student_id, name, mark):
    records = read_records(path)
    records.append((student_id, name, mark))
    write_records_sequential(path, records)

This is not the most efficient method, but it is clear and suitable for learning the idea.

Numeric and Text Keys

The examples keep student_id as text because identifiers may have leading zeroes. For example, "0012" and "12" may be different identifiers even though they represent the same integer value.

If a question says the key is numeric and numeric order matters, convert it before comparison:

if int(student_id) > int(target_id):
    return None

The difference matters because text order and numeric order are not always the same.

Text order:   "100" < "20"
Numeric order: 100 > 20

Use the representation that matches the meaning of the field.

Field typeKeep as text?Convert to number?
student ID with leading zeroesyesno
phone numberyesno
mark used for calculationnoyes
numeric product code where numeric order mattersmaybeyes if required

Tests for File Programs

File programs need tests for normal cases and edge cases. Do not only test a file with several well-formed records and a target in the middle.

Serial File Tests

Test caseExpected behaviour
empty filesearch returns None
target at first recordreturn first record
target at last recordreturn last record
target absentreturn None after checking all records
append one recordnew record appears at the end
append twicerecords remain in arrival order

Sequential File Tests

Test caseExpected behaviour
empty filesearch returns None
target at first recordreturn first record
target at last recordreturn last record
target absent before first keystop at first larger key
target absent between two keysstop when current key passes target
target absent after last keyreach end and return None
numeric key order requiredconvert keys before comparing

Example Test Code

def test_parse_record():
    assert parse_record("1001,Aisha,72\n") == ("1001", "Aisha", 72)
 
 
def test_find_record_missing(tmp_path):
    path = tmp_path / "students.txt"
    path.write_text("1001,Aisha,72\n1004,Bo,85\n", encoding="utf-8")
    assert find_record(path, "9999") is None

In a simple classroom script, you may not use tmp_path. You can still test the same idea by creating a small text file manually.

Common Mistakes

  • Forgetting that fields read from a file are strings.
  • Comparing numeric keys as text when numeric ordering is required.
  • Using "w" when the task says to append.
  • Forgetting "\n" when writing one record per line.
  • Using sequential-file early stopping on an unsorted file.
  • Not handling an empty file.
  • Assuming a file automatically becomes sorted after appending a record.
  • Forgetting to convert mark_text before doing calculations.

Debugging Table

SymptomLikely causeFix
old records disappearused "w" instead of "a" for appendinguse append mode for serial additions
two records appear on one lineforgot newline when writingwrite "\n" after each record
mark calculation failsmark is still a stringconvert using int(mark_text)
numeric order is wrongcompared numeric keys as stringsconvert keys before comparing
sequential search stops too earlyfile is not actually sorted by keysort the file or use serial search
search never finds an existing recordkey includes extra spaces or newlineuse .strip() and compare cleaned fields

How to Explain This in an Exam

For a serial file, say:

A serial file stores records in the order they are added. To search it, the program reads records one by one until the key is found or the end of file is reached.

For a sequential file, say:

A sequential file stores records in key order. During search, if the current key becomes greater than the target key, the search can stop because the target cannot appear later.

For parsing, say:

A line read from a text file is a string, so the program must split the line into fields and convert numeric fields before numeric comparison or calculation.

Check Your Understanding

  1. What order does a serial file use?
  2. What order does a sequential file use?
  3. Why can sequential search sometimes stop early?
  4. Why does parse_record() convert mark_text with int()?
  5. Why is "w" dangerous if you only want to add one record?
  6. Why might a student ID be kept as text instead of converted to an integer?

Answers:

  1. Arrival order.
  2. Key-field order.
  3. If the current sorted key has passed the target, the target cannot appear later.
  4. File data is read as text, but marks should behave like numbers.
  5. It overwrites the existing file contents.
  6. An identifier may have leading zeroes or may not be intended for arithmetic.