LambdaLabTM
Computer Science · Class 12 · Binary Files
Binary filesUpdating⏱️ 15 min read

Updating a Record

Amit's marks were entered wrongly and must be corrected. The record is in the middle of the file — there are four of them now, after the last lesson appended Neha — and this is the one operation where the obvious idea is the wrong one.

1Read them all, change one, write them all back

The same three steps as changing a text file, and for the same reason: records are different sizes, so there is no safe way to drop a new one into the middle.

Step 1 · Read them all
records = [...]

The reading loop from two lessons ago, collecting into a list. Then close the file.

Step 2 · Change it in memory
r[2] = new_marks

Plain list work. The file is not open and nothing has happened to it yet.

Step 3 · Write them all back
open(..., 'wb')

'wb' empties the file, then every record is dumped again — the changed one among them.

update_record.py
import pickle

roll = int(input('Roll number to update : '))
new_marks = int(input('New marks             : '))

# 1. read every record into a list
f = open('student.dat', 'rb')
records = []
try:
    while True:
        records.append(pickle.load(f))
except EOFError:
    pass
f.close()

# 2. change the one you want, in memory
found = False
for r in records:
    if r[0] == roll:
        r[2] = new_marks
        found = True

# 3. write them all back
f = open('student.dat', 'wb')
for r in records:
    pickle.dump(r, f)
f.close()

if found == True:
    print('Record updated.')
else:
    print('No record with roll number', roll)

f = open('student.dat', 'rb')
try:
    while True:
        print(pickle.load(f))
except EOFError:
    pass
f.close()
Output
Roll number to update : 3
New marks             : 72
Record updated.
[1, 'Ravi', 78]
[2, 'Meera', 91]
[3, 'Amit', 72]
[4, 'Neha', 88]
records.append(pickle.load(f))

Step 1. After this loop the whole file is in an ordinary Python list, and the file itself has been closed.

for r in records: if r[0] == roll:

Step 2. r is the record, so r[2] = new_marks changes the marks inside the list. Nothing on the disk has moved.

open('student.dat', 'wb')

Step 3. This EMPTIES the file — which is exactly what you want, because the list in memory now holds the correct version of everything.

found

The same flag as the search lesson. Without it, updating a roll number that does not exist rewrites the file and says nothing at all.

Step 3 destroys the file, on purpose
Between the open(..., 'wb') and the last dump(), the only complete copy of your data is the list in memory. If the program crashed in there, the file would be left half written. For schoolwork that is fine; a real program writes a new file and renames it afterwards, exactly as the text-file chapter did.

2The tempting wrong way: writing over it in place

You know seek() and tell(), and 'rb+' allows reading and writing through one handle. So why not note where the record started, change it, and write it straight back over itself?

in_place.py
import pickle

f = open('student.dat', 'rb+')

try:
    while True:
        position = f.tell()
        record = pickle.load(f)
        if record[0] == 3:
            record[2] = 72
            f.seek(position)
            pickle.dump(record, f)
            break
except EOFError:
    pass

f.close()

That program works. Change one number to another number of the same size and the new record takes exactly as many bytes as the old one, so it fits where it was. Now change the name instead:

in_place_broken.py
import pickle

f = open('student.dat', 'rb+')
try:
    while True:
        position = f.tell()
        record = pickle.load(f)
        if record[0] == 3:
            record[1] = 'Amitabh'
            f.seek(position)
            pickle.dump(record, f)
            break
except EOFError:
    pass
f.close()

f = open('student.dat', 'rb')
try:
    while True:
        print(pickle.load(f))
except EOFError:
    pass
f.close()
Output
[1, 'Ravi', 78]
[2, 'Meera', 91]
[3, 'Amitabh', 65]
Traceback (most recent call last):
  File "in_place_broken.py", line 20, in <module>
    print(pickle.load(f))
          ^^^^^^^^^^^^^^
_pickle.UnpicklingError: invalid load key, '\x10'.
'Amitabh' is three letters longer than 'Amit'
So the new record needed more bytes than the old one, and those extra bytes landed on top of whatever came next. The file is now damaged: the first three records read back perfectly and the fourth is rubbish. Writing in place is only safe when the new record is exactly the same size as the old one, and you can rarely promise that.
What to write in the exam
Use the three-step version. It is correct whatever changes, it is the answer the marking scheme expects, and it is shorter to write. Keep 'rb+' and seek() for knowing why the other way is dangerous.

3Deleting a record is the same three steps

You never remove a record from a file. You write the file again without that record:

delete_record.py
import pickle

f = open('student.dat', 'rb')
records = []
try:
    while True:
        records.append(pickle.load(f))
except EOFError:
    pass
f.close()

kept = []
removed = 0
for r in records:
    if r[0] == 2:
        removed = removed + 1
    else:
        kept.append(r)

f = open('student.dat', 'wb')
for r in kept:
    pickle.dump(r, f)
f.close()

print('Records removed:', removed)
Output
Records removed: 1

4Try it

The file is created first, so the program runs on its own. Change the roll number, or update the name instead of the marks:

updating.py

5Recap

Read all, change one, write all back

The three steps. Step 3 opens the file in 'wb', which empties it before the corrected records go in.

The change happens in a list

Between steps 1 and 3 the file is closed and the data is an ordinary Python list.

Keep the found flag

Otherwise an update of a roll number that is not there rewrites the file and reports nothing.

'rb+' with seek() is the trap

It only works while the new record pickles to exactly the same number of bytes.

A bigger record damages the file

The extra bytes land on the next record. UnpicklingError: invalid load key.

Deleting is the same shape

Build a list of the records you are keeping, and write that list back.

✍️ Now write these yourself
  1. 1

    Update a student's name rather than their marks.

    Hint · r[1] = new_name — and use the three-step version.

  2. 2

    Give every student five extra marks in one run.

    Hint · No if at all: change every record in the list, then write it back.

  3. 3

    Delete a record by roll number, and report how many were removed.

    Hint · Build the kept list; do not try to remove from the file.

  4. 4

    Update a roll number that is not in the file and check the file afterwards.

    Hint · Every record is still there — rewritten identically.

Quick Check

What are the three steps of updating a record in a binary file?

Quick Check

Why is writing over a record in place dangerous?

Quick Check

Which mode does step 3 use?

Quick Check

How do you delete a record?