Searching a Binary File
A binary file has no index and no way to jump to a record. Searching is therefore the reading loop with an if in it — and the half of the answer students lose marks for is what happens when nothing matches.
1There is no shortcut: you read from the start
The records sit one behind another. Nothing at the front of the file lists what is inside it, and there is no way to ask for “the record with roll number 2”. So a search is: read a record, check it, read the next.
import pickle
def search(roll):
f = open('student.dat', 'rb')
found = False
try:
while True:
record = pickle.load(f)
if record[0] == roll:
print('Found:', record[1], 'scored', record[2])
found = True
break
except EOFError:
pass
f.close()
if found == False:
print('No student with roll number', roll)
search(2)
search(9)Found: Meera scored 91 No student with roll number 9
found = FalseSet BEFORE the loop. It remembers whether anything ever matched — the loop itself cannot tell you that after it has finished.
if record[0] == roll:The test. record[0] is the roll number, because that is the position it was written in.
found = TrueThe flag is raised the moment something matches. This one line is what the last if depends on.
breakRoll numbers are unique, so there is no point reading the rest of the file. Leave it out if several records could match.
if found == False:After the loop, and only now. Put this inside the loop and it prints 'not found' once for every record that is not the one you wanted.
Looking for roll number 3. Each load() brings back one record to test.
—record[0] == 3 → —found = FalseThe file is open and the pointer is at the start. Nothing has been read.
found, a search for a roll number that is not there prints nothing at all — and a program that says nothing looks broken to whoever is using it.2Searching for everything that matches
When several records could match — every student above 80, every book under 200 rupees — the shape barely changes. Take out the break, and let the loop see the whole file:
import pickle
f = open('student.dat', 'rb')
found = False
try:
while True:
record = pickle.load(f)
if record[2] > 80:
print(record[1], 'scored', record[2])
found = True
except EOFError:
pass
f.close()
if found == False:
print('Nobody scored more than 80.')Meera scored 91
For a unique key such as a roll number or an admission number. Once you have found it, reading on is wasted work.
For a condition several records can meet. The loop runs to the end of the file and prints each one as it comes.
3Asking the user what to look for
import pickle
roll = int(input('Roll number to find: '))
f = open('student.dat', 'rb')
found = False
try:
while True:
record = pickle.load(f)
if record[0] == roll:
print('Roll :', record[0])
print('Name :', record[1])
print('Marks :', record[2])
found = True
break
except EOFError:
pass
f.close()
if found == False:
print('Record not found.')Roll number to find: 3 Roll : 3 Name : Amit Marks : 65
input() gives a string, and the roll number in the record is a number. '3' == 3 is False, so without int() the search finds nothing, every time, with no error to explain why.4Try it
The file is written first so the program is complete. Change the roll number, or search on the name instead:
5Recap
No index, no jumping. Read from the start and test each record as it arrives.
The flag that remembers whether anything ever matched.
Inside it, 'not found' would print once per record that is not the one you want.
Roll numbers do not repeat, so stop as soon as you have it.
Several records may match; the loop should see all of them.
'3' never equals 3, and the search would quietly fail.
- 1
Search for a student by name instead of roll number.
Hint · record[1] == name — and no int() this time.
- 2
Display every student who scored less than 70.
Hint · The condition search, with no break.
- 3
Count how many records match, instead of printing them.
Hint · A counter instead of a flag — and 0 is its own “not found”.
- 4
Take the
foundflag out and search for a roll number that is not in the file.Hint · The program prints nothing and looks broken. That is the point of the flag.
Why does a binary-file search have to read from the start?
Where does 'record not found' belong?
A search for roll number 3 finds nothing, even though record [3, 'Amit', 65] is in the file. What is the likely cause?
When should the search loop NOT use break?