SDD11 — File Handling: Reading
- I can open, read from, and close a sequential text file in Python
- I can read a CSV file's contents and split it into individual lines and fields
- I can explain why data read from a file must sometimes be converted before it can be used
- I can use
open(),read(), andclose()to load the contents of a text file into my program - I can use
.strip()to remove unwanted whitespace or newline characters from data read from a file - I can use
split()twice — once to separate lines, once to separate fields — to turn CSV text into usable data - I can use
int()to convert a numeric field read from a file, and explain why this step is necessary
Download these into the same PyCharm project folder as your .py file before working through the examples and Task Set A — the code in this lesson expects notice.txt and tuckshop.csv to already exist alongside it.
"Higher Computing".split(" ")?23 % 5?Key vocabulary
.strip()Reading data from a file
Why use file handling at all?
Every program built so far in this course has stored its data only in variables and arrays — the moment the program stops running, that data is gone. File handling solves this by reading data from, or writing data to, a file stored outside the program, so it survives between one run and the next. This lesson covers reading; SDD12 covers writing. Higher only requires sequential file access, meaning a file's contents are read in order from the beginning, not jumped to at a specific position.
Opening, reading, and closing a file
Three pre-defined functions/methods handle the basic lifecycle of reading a file. open(filename, mode) opens a file and returns a file object that the rest of the code works with; the mode "r" means read. Calling .read() on that file object returns the entire contents of the file as one single string — including any newline characters that separated the original lines. Finally, .close() releases the file once the program is finished with it. Forgetting to close a file can leave it locked or cause data not to be saved properly when writing (SDD12) — always close what was opened.
From one big string to individual lines
.read() returns everything as a single string, with each original line separated by a newline character, "\n". To work with the data one line at a time, that whole string must be broken apart using split("\n") — the pre-defined function met in SDD10, used here with a newline as the delimiter instead of a space. This turns one long string into a list, with each item in the list being one line (one record) from the file.
From one line to individual fields — reading CSV data
A CSV file stores several fields on each line, separated by commas — for example Chocolate,75,30 stores a name, a price, and a stock level as one line. Once split("\n") has produced a list of individual lines, split(",") is applied again, this time to each individual line, to break it into its separate fields. This is why reading a CSV file typically needs split() used twice, with two different delimiters: once for the whole file (splitting on "\n" to get lines), and once per line (splitting on "," to get fields).
Converting fields after reading them
Every single value produced by split() is a string — even a field that looks like a whole number, such as "75", is read as the text characters 7 and 5, not the number 75. Any field that needs to be used as a number (added, compared, or used in a calculation) must be explicitly converted using int() (SDD10) before it can be used that way. Skipping this step doesn't raise an error immediately — Python will happily let two string fields be joined with + — but the result is string concatenation, not addition, producing a wrong answer that runs without complaint.
Cleaning up with .strip()
If a file ends with a newline character (which most text editors add automatically), splitting the whole file's text on "\n" produces one extra, empty item at the end of the list. Similarly, the very last field on a line can end up with a trailing "\n" still attached to it if .read()'s result isn't cleaned up first. Calling .strip() on the whole file's text, before splitting it into lines, removes this leading/trailing whitespace and prevents both problems.
file = open("tuckshop.csv", "r") — opens the file in read mode and returns a file object.fileText = file.read().strip() — reads the whole file as one string, then removes any trailing newline.lines = fileText.split("\n") then, for each line, fields = line.split(",") — two separate delimiters, two separate steps.int() before being stored, e.g. as an Item record.file.close() — always close a file once the program is finished reading from it.Worked examples
notice.txt contains one line of text: Tuck shop closes early on Fridays.
file = open("notice.txt", "r")
noticeText = file.read()
file.close()open() returns a file object in read mode; .read() loads the entire file's contents into noticeText as one string; .close() releases the file.noticeText is "Tuck shop closes early on Fridays" — a single string, ready to be printed or processed further.tuckshop.csv contains five lines, one per item:
Chocolate,75,30 Crisps,63,45 Juice,90,20 Flapjack,110,15 Sweets,50,60
file = open("tuckshop.csv", "r")
fileText = file.read().strip()
file.close()
lines = fileText.split("\n")
for line in lines:
fields = line.split(",")
print(fields)lines has 5 items, one per row. Each fields is a 3-item list of strings, e.g. ['Chocolate', '75', '30'] — note every value, including '75' and '30', is still text, not a number.Item @dataclass from SDD6–10:
from dataclasses import dataclass
@dataclass
class Item:
name: str
price: int
stock: int
itemRecords = []fields[1] and fields[2] are passed through int(), but fields[0] (the name) is left as a string:
for line in lines:
fields = line.split(",")
newItem = Item(fields[0], int(fields[1]), int(fields[2]))
itemRecords.append(newItem)itemRecords[0] is Item(name='Chocolate', price=75, stock=30) — price and stock are now genuine integers, so itemRecords[0].stock can be used directly in a calculation.totalStock = 0
for item in itemRecords:
totalStock = totalStock + item.stockint() and round() to recall SDD10's distinction:
totalPrice = 0
for item in itemRecords:
totalPrice = totalPrice + item.price
averagePrice = totalPrice / len(itemRecords)totalStock is 170 (30+45+20+15+60). averagePrice is 77.6; int(averagePrice) gives 77 (truncated) while round(averagePrice) gives 78 (rounded) — neither of these calculations would have been possible if price and stock had been left as strings straight from the file.line, containing the text "Muffin,120,18". Write the Python code needed to split this line into its three fields and store the price as an integer in a variable called price.
- Forgetting to convert numeric fields with
int(). Every field fromsplit()is a string. Adding two unconverted numeric fields with+silently concatenates them instead of adding them (e.g."75" + "30"gives"7530", not105) — this runs without any error, making it easy to miss. - Splitting only once. Reading a CSV file needs
split()twice — once on"\n"for lines, once on","per line for fields. Applying it only once leaves each "record" as one unsplit comma-separated string. - Forgetting
.strip(). If the file ends with a newline, splitting on"\n"produces an extra empty string at the end of the list, and the very last field on a line can retain a trailing"\n"if the whole read wasn't stripped first. - Assuming every line has the same number of fields. A malformed or incomplete line produces a shorter
fieldslist than expected, so accessing e.g.fields[2]raises anIndexErrorif that line is missing a value. - Forgetting to close the file. Always pair
open()with a matching.close()once reading is finished.
When describing how to read CSV data, name the exact sequence: open, read, split on newline, split each line on comma, convert fields, close — a vague answer like "read the file and get the data out" will not gain full marks. If a question shows a field being used in a calculation, always check whether an int() conversion is missing before assuming the rest of the logic is wrong.
Task Set A — Core questions
open(), opens a file for reading?.read() return when called on an open file object?"Muffin,120,18". What is the value of "Muffin,120,18".split(",")[1]?"Muffin,120,18".split(",")[1], before any further conversion?"75" + "30" produce, if the int() conversion is forgotten?split() to be called twice, using two different delimiters. (3 marks).strip() is not called before splitting the whole text on "\n"?"tuckshop.csv" for reading, reads and strips its contents, splits it into lines, then splits each line into fields and prints the resulting list of fields for every line. Remember to close the file.file = open("tuckshop.csv", "r")
fileText = file.read().strip()
file.close()
lines = fileText.split("\n")
for line in lines:
fields = line.split(",")
print(fields)
stock field should be converted with int() immediately after being read from a CSV file, rather than left as a string until it is needed later in the program. (3 marks)Task Set B — Extension
fields[2] on that line, and explain why.csv module. Suggest one advantage it might have over the manual split()-based approach used in this lesson, and one reason a learner might still be taught the manual approach first.Higher Computing Science → Software Design & Development → SDD11
Double period. Reviewed a colleague's equivalent teaching material (Lessons 7–8, file handling) ahead of this build — confirmed the manual double-split() approach (no csv module) and .strip()-after-.read() are both consistent with what's taught in the parallel course, so this lesson matches that convention deliberately, not by coincidence.
Suggested timing: 5 min warm-up + vocab · 25 min notes + file-flow pipeline walkthrough (run each step live in the Python shell rather than only showing static code) · 30 min examples 1–4 · 10 min "now you try" · 40 min Task Set A · Task Set B as homework/extension.
Key misconception: pupils very reliably forget that every field from split() is a string, including ones that look numeric — the silent string-concatenation bug ("75" + "30" → "7530") is worth demonstrating live, since it produces a plausible-looking but wrong number rather than an obvious error.
Bug to avoid repeating from the colleague's material when SDD12 (writing) is built: one worked example there concatenated a non-string dataclass field directly with + without wrapping it in str() first, which raises a TypeError — verified by actual Python execution this session. SDD12 must cast every non-string field with str() before writing it out.
SQA command words covered: explain, describe, predict, write code.