📌 Snapshot
- Learn text and binary files, open modes, read and write methods, seek and tell, and pickle with traces.
- Why variables vanish when a program ends, and how files on secondary storage keep your data safe.
- Every access mode compared in one table, and the read, readline and readlines methods side by side.
- Step by step traces of seek and tell, and of how pickle saves and reloads Python objects.
📖 Detailed Notes
Written and reviewed by Rohit Singh, Computer Science & Commerce faculty at UniDrill (MCA, Osmania University · 6 years teaching). Based on NCERT Computer Science Class XII, Chapter 2.
Where does your data go when the program ends?
Imagine a marks entry program. You type in 40 students' marks, close the program, and open it the next day. Everything is gone. Variables live in memory only while the program runs. To keep data for later, a program must store it in a file: a named location on secondary storage (hard disk, pen drive, SSD) where data stays permanently.
This chapter follows the life of a file in Python: open it, read or write it, move around in it, and close it. Then it adds one powerful trick, the pickle module, which stores whole Python objects such as lists and records.
Text files and binary files
Every file stores bytes, but what the bytes mean differs.
| Feature | Text file | Binary file |
|---|---|---|
| Stores | A sequence of characters: letters, digits and symbols | Raw bytes (0s and 1s) that stand for images, audio, video, compressed files, programs |
| Examples | .txt, .py, .csv |
.jpg, .mp3, .exe, .dat |
| Encoding | Characters saved as bytes using ASCII, Unicode or another scheme | The bytes mean whatever the program that made them says |
| Line ending | Each line ends with an End of Line (EOL) character, \n in Python |
No lines |
| In a text editor | Readable | Garbage values |
| Damage | A changed character affects only that character | Even a single changed bit can make the file unreadable |
| Mode letter | Default | Add b, as in rb or wb |
Why binary files break so easily. A binary file has a precise structure that its own software expects. A JPEG image, for instance, is a carefully ordered stream of bytes. Change one bit in the wrong place and the software can no longer decode it. Text has no hidden structure to break, which is why you can read a damaged text file in any editor.
Beyond the textbook. For the exam: in a text file each line ends with the single EOL character \n. In reality: Windows stores line endings as two characters, but Python quietly converts them to \n when it reads a text file and converts back when it writes. Your code sees the same \n on every system.
Opening a file
The built in function open() links your program to a file:
file_object = open(file_name, access_mode)
It returns a file handle, stored in file_object, which you use for every later operation. The second argument is optional: if you leave it out, the file opens in read mode (r) as a text file. The file object carries three useful attributes.
| Attribute | Gives |
|---|---|
file_object.closed |
True if the file is closed |
file_object.mode |
The access mode used |
file_object.name |
The file name |
The access mode decides what you may do and where the offset (the current position) starts. This table is the most tested one in the chapter.
| Mode | You can | Offset starts | File missing | Existing data |
|---|---|---|---|---|
r |
Read only | Beginning | Error | Kept |
rb |
Read only, binary | Beginning | Error | Kept |
r+ |
Read and write | Beginning | Error | Kept (writing overwrites from the offset) |
w |
Write only | Beginning | File is created | Erased |
wb+ |
Read and write, binary | Beginning | File is created | Erased |
a |
Append (write at the end) | End | File is created | Kept |
a+ |
Append and read | End | File is created | Kept |
Two quick rules cover the whole table. Modes that start with r never create a file, so they need it to exist. Modes with w always erase, so a careless open(name, "w") on an existing file destroys its contents. Binary versions simply add b, and wb and ab are the modes used with pickle.
Worked example: what is in the file? The file a.txt is opened and closed three times in a row. What does it contain at the end?
| Step | Statements | Mode | File content afterwards |
|---|---|---|---|
| 1 | Write Hi |
w |
Hi |
| 2 | Write Bye |
a |
HiBye |
| 3 | Write X |
w |
X (opening in w erased everything) |
The wrong step is to read the third w as "write more". Write mode starts from nothing every time.
Closing a file, and the with clause
file_object.close() pushes any unsaved data to the file and frees the memory used. This matters because write() first puts data in a buffer (a holding area in memory). The data reaches permanent storage only when the file is closed, or when you call flush() to force it out. A program that crashes before closing can lose data still sitting in the buffer.
The with clause removes the risk:
| Code |
|---|
with open("notes.txt", "r") as f: |
data = f.read() |
print(f.closed) |
| Output |
|---|
True |
The file is closed automatically when control leaves the with block, even if an exception occurs inside it. No explicit close() is needed, which is why modern code prefers with. It does the job of a try with a finally that closes the file.
Writing to a text file
| Method | Argument | Returns | Adds a newline? |
|---|---|---|---|
write(s) |
One string | The number of characters written | No |
writelines(seq) |
A list or tuple of strings | Nothing (None) |
No |
Both methods need strings. To write a number, convert it first with str(), otherwise Python raises TypeError. Neither method adds \n for you, so you put line breaks in yourself.
Worked example: write and writelines. What does this program print, and what ends up in the file?
| Code |
|---|
f = open("a.txt", "w") |
print(f.write("Hi\n")) |
f.writelines(["ab", "cd", "ef"]) |
f.write(str(25)) |
f.close() |
| Output |
|---|
3 |
write("Hi\n") returns 3, counting H, i and the newline. The next two calls add no line breaks, so everything joins up.
| Line of a.txt | Content |
|---|---|
| 1 | Hi |
| 2 | abcdef25 |
Reading from a text file
Suppose poem.txt holds three lines, with no newline after the last one:
| Line | Text | Characters (with newline) |
|---|---|---|
| 1 | Hello everyone |
15 |
| 2 | Writing multiline strings |
26 |
| 3 | This is the third line |
22 |
| Call | Returns | Type |
|---|---|---|
read() |
The whole file, 'Hello everyone\nWriting multiline strings\nThis is the third line' |
One string |
read(5) |
The next 5 bytes, 'Hello' (for plain English text, 5 characters) |
String |
readline() |
One line including its newline, 'Hello everyone\n' |
String |
readlines() |
['Hello everyone\n', 'Writing multiline strings\n', 'This is the third line'] |
List of strings |
read().splitlines() |
['Hello everyone', 'Writing multiline strings', 'This is the third line'] |
List without newlines |
Notice that readlines() keeps the \n at the end of each line, while splitlines() removes them. The last line has no \n only because the file does not end with one. When the end of the file is reached, readline() returns an empty string '', not None. That empty string is how a loop knows to stop.
| Code |
|---|
f = open("poem.txt", "r") |
line = f.readline() |
while line: |
print(line, end="") |
line = f.readline() |
f.close() |
The loop is true while line holds text. An empty string counts as false, so the loop ends at the end of the file.
Pause and predict: after two readline() calls on poem.txt, what does read(4) return?
Check your answer: 'This'. Each readline() moves the offset past its line, so after two calls the offset is at the start of line 3, and read(4) takes the first four characters of it.
tell() and seek(): moving inside a file
A file object remembers its offset, the number of bytes from the beginning where the next read or write will happen. tell() reports it. seek(offset, reference_point) moves it. The reference point is optional and defaults to 0.
| reference_point | Offset is counted from |
|---|---|
| 0 (default) | The beginning of the file |
| 1 | The current position |
| 2 | The end of the file |
Worked example: tracing the offset. Using poem.txt from above:
| Statement | Result | tell() afterwards |
|---|---|---|
f = open("poem.txt") |
File opens in read mode | 0 |
f.read(5) |
'Hello' |
5 |
f.readline() |
' everyone\n' (the rest of line 1) |
15 |
f.readline() |
'Writing multiline strings\n' |
41 |
f.seek(0) |
Back to the start | 0 |
f.seek(10) |
Moves to byte 10 | 10 |
f.read(4) |
'yone' |
14 |
f.read() |
The remaining 49 characters | 63 |
f.readline() |
'' (end of file) |
63 |
Everything is counted in bytes, never in lines. tell() after reading line 1 is 15, not 1. This is why reading a file twice needs seek(0) in between: after the first full read the offset sits at the end.
Beyond the textbook. For the exam: seek(offset, reference_point) accepts 0, 1 and 2 as reference points. In reality: a file opened in text mode only allows seek(offset, 0) freely. Moving by a non zero offset from the current position or from the end raises an error, and only binary files accept all three reference points. For the same reason, the offsets you pass to seek() in text mode should come from earlier tell() calls or be 0.
Writing and then reading the same file
Mode w+ creates (or erases) a file and lets you both write and read. After writing, the offset is at the end, so seek(0) is needed before reading back.
| Code |
|---|
f = open("marks.txt", "w+") |
f.write("Asha 85\n") |
f.write("Ravi 72\n") |
f.seek(0) |
print(f.read()) |
f.close() |
| Output |
|---|
Asha 85 |
Ravi 72 |
A short program can then total the marks. Each line is split into words with split(), and the second word is converted to a number.
| Code |
|---|
total = 0 |
with open("marks.txt") as f: |
for line in f: |
parts = line.split() |
total = total + int(parts[1]) |
print(total) |
| Output |
|---|
157 |
Pause and predict: a file data.txt contains Hello. It is opened with open("data.txt", "a+"), and the very next statement is print(f.read()). What is printed?
Check your answer: An empty line. Mode a+ starts the offset at the end of the file, so read() finds nothing to read. A seek(0) first would let it read Hello.
The pickle module: saving whole objects
A text file can only hold text, so a record such as [101, "Asha", 95] would come back as a string, not as a list. Python's pickle module solves this. Pickling (serialisation) turns a Python object into a stream of bytes that can be stored in a binary file or sent over a network. Unpickling (de-serialisation) turns the bytes back into the original object, with the same structure and data types.
The steps never change. Import pickle, open the file in binary mode, call dump() or load(), then close it.
| Function | Syntax | File mode needed | What it does |
|---|---|---|---|
dump() |
pickle.dump(data_object, file_object) |
wb (new) or ab (add to the end) |
Pickles one object into the file |
load() |
store_object = pickle.load(file_object) |
rb |
Unpickles the next object from the file |
| Code |
|---|
import pickle |
records = [[101, "Asha", 95], [102, "Ravi", 88]] |
f = open("emp.dat", "wb") |
for rec in records: |
pickle.dump(rec, f) |
f.close() |
f = open("emp.dat", "rb") |
try: |
while True: |
print(pickle.load(f)) |
except EOFError: |
pass |
f.close() |
| Output |
|---|
[101, 'Asha', 95] |
[102, 'Ravi', 88] |
Each dump() writes one object, so several records need a loop. Each load() reads the next one in the same order. When the objects run out, load() raises EOFError. This is exactly why the reading loop sits inside a try with except EOFError: the error is the signal for "no more records", which links this chapter directly to Exception Handling.
Worked example: how many records? The program above runs three times. How many records does emp.dat hold after each run, if the open mode changes as shown?
| Run | Mode used | Records dumped | Records in file afterwards |
|---|---|---|---|
| 1 | wb |
3 | 3 |
| 2 | ab |
2 | 5 (appended after the old ones) |
| 3 | wb |
1 | 1 (the old records are erased) |
Beyond the textbook. For the exam: pickle stores any Python object in a binary file. In reality: never unpickle a file that came from someone you do not trust. Loading a pickle can run code hidden inside it, so pickle is meant only for data your own programs wrote. For data you exchange with other people or systems, formats such as CSV are the safer choice.
Exam traps
| Trap | Why it tempts | Truth |
|---|---|---|
open(name, "w") adds to the file |
"Write" sounds like "add" | w erases existing content; a adds |
The default mode of open() is w |
Writing is the more active mode | The default is r, text |
writelines() puts each item on its own line |
The name suggests lines | It adds no newlines, so items join up |
readline() returns None at the end |
Many functions return None for nothing |
It returns an empty string '' |
tell() returns the line number |
We think in lines | It returns the byte offset |
The default reference_point of seek() is 1 |
Current position feels natural | The default is 0, the beginning |
pickle.dump() works on a file opened with w |
Writing is writing | It needs binary mode wb or ab; a text mode file raises TypeError |
write() accepts a number |
Print accepts numbers | It needs a string, so use str(25) |
60-second revision
| Idea | Remember |
|---|---|
| File | Named location on secondary storage; keeps data after the program ends |
| Text vs binary | Text has characters and EOL \n; binary has raw bytes and mode letter b |
| open() | open(file_name, access_mode) returns a file handle; default is r text |
| Modes | r, rb, r+ start at the beginning; w, wb+ erase; a, a+ start at the end |
| close and with | close() flushes the buffer; with closes automatically, even on error |
| Writing | write() takes a string and returns the character count; writelines() takes a sequence and returns None |
| Reading | read() is everything, readline() is one line, readlines() is a list of lines |
| End of file | readline() and read() give '' |
| tell and seek | tell() gives the byte offset; seek(offset, 0 or 1 or 2) moves it |
| pickle | dump() with wb or ab; load() with rb; EOFError ends the loop |
Where this chapter connects
The finally clause and the with statement are two ways to guarantee a file closes, so revisit Exception Handling in Python. Later chapters read data back from files too, for example in Data Handling using Pandas I.
🎯 Practice MCQs
First 3 questions free · create a free account to unlock the rest — answers & explanations included, no payment needed
Q1. Which call opens the file data.txt for both reading and writing, with the file offset at the beginning?
▸ Show answer & explanation
Answer: B
Mode r+ allows reading and writing from the beginning. Mode a+ also reads and writes, but its offset starts at the end. Mode rb is read only, and mode w is write only and erases the file.
Q2. Which statement about the write() method of a text file is correct?
▸ Show answer & explanation
Answer: C
write() works through a buffer, so closing the file (or calling flush) is what saves the data. It returns the number of characters written, not None, and it accepts only strings, so an integer must first be converted with str().
Q3. A file myfile.txt has three lines: Hello everyone, Writing multiline strings and This is the third line, with no newline after the last line. What does print(f.readlines()) show for a file opened in r mode?
▸ Show answer & explanation
Answer: C
readlines() returns a list, and every element keeps its trailing newline except the last, because the file does not end with one. Option B shows what splitlines() would give. Options A and D have the wrong data type.
🔒 12 more practice MCQs
Create a free account to unlock every MCQ in this chapter — answers and explanations included. No payment needed.
Already registered? Just log in and they'll all appear here.
Q4. Match List I with List II. List I: (i) tell() (ii) seek() (iii) readline() (iv) read() with no argument. List II: (p) Reads one complete line including the newline (q) Returns the current byte position (r) Moves the file object to a given offset (s) Reads the whole file as one string. Which option is correct?
▸ Show answer & explanation
Answer: B
tell() reports the position, seek() changes it, readline() reads one line, and read() with no argument reads everything. The other options swap at least two of these pairs.
Q5. Assertion (A): Opening a file with the with clause removes the need to call close() explicitly. Reason (R): The with clause closes the file automatically when control leaves the block, even if an exception occurs.
▸ Show answer & explanation
Answer: A
The automatic closing on leaving the block, even after an error, is exactly what makes an explicit close() unnecessary. So R explains A.
Q6. A list rec = [101, "Arjun", 85.5] has to be saved in the binary file marks.dat. Which approach is correct?
▸ Show answer & explanation
Answer: D
dump() needs the file opened in binary write mode, wb. Mode r is read only and text, mode rb is for load(), and load() reads an object instead of saving one.
Q7. Which of these statements about binary files are correct? (1) They store data as a stream of bytes and are not human readable. (2) They can be read correctly in any text editor. (3) Even a single bit change can corrupt them. (4) Python programs can both read and write them.
▸ Show answer & explanation
Answer: B
A text editor shows garbage for a binary file, so statement 2 is false. Statements 1, 3 and 4 are all true.
Q8. What does f.seek(10, 0) do?
▸ Show answer & explanation
Answer: D
The second argument 0 means the beginning of the file, so the offset 10 is counted from there. Reference point 1 is the current position and 2 is the end, which rules out options A and B. seek() does move the object, so option C is wrong.
Q9. Consider: (1) f = open("a.txt", "w") (2) f.write("Hi") (3) f.close() (4) f = open("a.txt", "a") (5) f.write("Bye") (6) f.close() (7) print(open("a.txt").read()). What is printed?
▸ Show answer & explanation
Answer: A
Mode w creates the file with Hi. Mode a keeps that content and adds Bye at the end. Option B would be right only if the second open used mode w.
Q10. A file contains the text Hello World. After f.read(5) on a freshly opened file, what does f.tell() return?
▸ Show answer & explanation
Answer: C
read(5) consumes five bytes, so the offset moves from 0 to 5. The value 11 would be the offset after reading the whole text, and 0 is the offset before any reading.
Q11. Which exception does pickle.load() raise when no more objects are left in the file?
▸ Show answer & explanation
Answer: B
load() signals the end of the file with EOFError, which is why reading loops catch it with an except block. ValueError and IOError describe other problems, and StopIteration belongs to iterators.
Q12. What is the default value of reference_point in seek()?
▸ Show answer & explanation
Answer: A
If the second argument is omitted, the offset is counted from the beginning of the file. Options B and C name the other two reference points.
Q13. Assertion (A): A binary file cannot be read meaningfully in a text editor. Reason (R): A binary file stores raw bytes, not characters meant to be displayed as text.
▸ Show answer & explanation
Answer: D
Because the bytes are not text characters, an editor shows garbage values. R is the reason behind A.
Q14. Consider: (1) f = open("x.txt", "w") (2) f.writelines(["a", "b", "c"]) (3) f.close() (4) print(open("x.txt").read()). What is printed?
▸ Show answer & explanation
Answer: C
writelines() writes the strings as they are and adds no newline characters, so they join into abc. For separate lines each string would have to end with a newline.
Q15. A file data.txt contains the text Hello. It is opened with open("data.txt", "a+") and the next statement is print(f.read()). What is printed?
▸ Show answer & explanation
Answer: A
Append mode places the offset at the end of the file, so read() finds nothing and returns an empty string. A seek(0) before reading would have returned Hello. Mode a+ does allow reading, which rules out option C.
📊 Previous-Year Questions
Practise with real CUET Computer Science previous-year papers — every question solved, with the correct answer and a step-by-step explanation.
View solved CUET PYQ papers →Ready to drill Computer Science?
Unlock all MCQs, chapter tests, mocks & PYQs for ₹199/year.
Get UniDrill Pro