CSIP12.in
Back to List
Calculating...
UNIT 1 : CH 5 Jun 26, 2026

πŸ” File Handling in Python (Binary & CSV file)

### πŸ₯’ Pickling, UnPickling & Structured Data Storage!

> You've mastered text files β€” now level up! **Binary files** let you store *any Python object* directly (lists, dicts, class objects!) and **CSV files** let you store *structured tabular data* that opens straight in Excel! πŸš€

---

::: grid
::: card 5.5.1 | Binary File Basics | Creating, opening and closing binary files with the right modes | wb, rb, ab, rb+
::: card 5.5.2 | Pickling | Serialize any Python object and write it to a binary file | pickle.dump()
::: card 5.5.3 | UnPickling | Deserialize and restore Python objects back from binary files | pickle.load()
::: card 5.5.4 | Searching | Find specific records by looping through a binary file | EOFError, loop
::: card 5.5.5 | Updating | Modify records using the Read-All β†’ Modify β†’ Write-All pattern | update, rewrite
::: card 5.6 | CSV Files | Read and write structured comma-separated tabular data | csv module, reader, writer
:::

---

## πŸ”’ 5.5 Working with Binary Files

### What Makes Binary Files Special?

Text files are great for storing simple strings β€” but what if you want to save a **complete Python dictionary**, a **list of student records**, or even a **custom class object** directly to disk? That's where binary files shine!

Binary files store data in the **same format as Python's internal memory (RAM) representation** β€” raw bytes. This means:

- βœ… **Any Python object** can be stored β€” lists, dicts, tuples, class instances
- βœ… **No data type conversion** needed (text files force everything into strings)
- βœ… **Faster** for complex, structured records
- ❌ **Not human-readable** β€” you need Python to open and decode them

> [!NOTE]
> **Memory Trick:** Text files are like writing a letter in English β€” anyone can read it. Binary files are like a **WhatsApp voice note stored as bytes** β€” only the app (Python) can decode and play it back! 🎀

---

### 🎁 The `pickle` Module β€” Python's Magic Serializer!

Python handles all binary file serialization through the built-in **`pickle` module**. It converts Python objects into a byte stream (and reconstructs them back perfectly).

> [!RULE]
> **Two core pickle functions:**
> - `pickle.dump(object, file)` β†’ **Serialize** and **write** object to binary file
> - `pickle.load(file)` β†’ **Read** from binary file and **reconstruct** back to Python object
>
> The conversion Python object β†’ bytes is called **Pickling** (Serialization).
> The reverse, bytes β†’ Python object, is called **UnPickling** (Deserialization).

---

### πŸ—ΊοΈ Pickling & UnPickling β€” The Full Picture

πŸ₯’ Pickling β€” Writing to Binary File
```mermaid
flowchart LR
A["🐍 Python Object\nlist / dict / object"]
B["open() with 'wb'\nOpen file for writing"]
C["pickle.dump()\nSerialize to bytes"]
D["πŸ’Ύ Binary File\nstudents.dat"]

A --> B --> C --> D

classDef tryNode fill:none;
classDef elseNode fill:none;
classDef normalNode fill:none;

class A elseNode;
class B,C tryNode;
class D normalNode;
```
πŸ“¦ Unpickling β€” Reading from Binary File
```mermaid
flowchart LR
D["πŸ’Ύ Binary File\nstudents.dat"]
E["open() with 'rb'\nOpen file for reading"]
F["pickle.load()\nDeserialize bytes"]
G["🐍 Python Object\nRestored perfectly!"]

D --> E --> F --> G

classDef tryNode fill:none;
classDef elseNode fill:none;
classDef normalNode fill:none;

class D normalNode;
class E,F tryNode;
class G elseNode;
```

---

### πŸ”‘ 5.5.1 Creating / Opening / Closing Binary Files

Binary files use the **same `open()` function** as text files β€” just add **`b`** to the mode string!

- **`'wb'` β€” Write Binary πŸ“¦**
* Opens for **writing in binary mode**
* Creates new file if it doesn't exist
* **Overwrites and destroys** existing content (like `'w'` in text mode) ⚠️
* Use for: Creating a fresh binary file from scratch

- **`'rb'` β€” Read Binary πŸ“–**
* Opens for **reading in binary mode** β€” file must exist!
* Raises `FileNotFoundError` if file is missing
* Use for: Reading, displaying, or searching records

- **`'ab'` β€” Append Binary βž•**
* Opens for **appending in binary mode**
* Adds new data at the very end; **preserves all existing records**
* Use for: Adding new records without touching old ones

- **`'rb+'` β€” Read + Write Binary πŸ”€**
* Opens for **both reading and writing** in binary mode
* File **must already exist** β€” does NOT create a new file
* Use for: Complex operations needing both read and write

> [!IMPORTANT]
> **Board Exam Hotspot:** Binary files in CBSE exams almost always use the `.dat` extension (e.g., `students.dat`). Python doesn't enforce this β€” it's just convention. Always `import pickle` at the top of any binary file program!

```python
import pickle

# The standard pattern for binary file operations
f = open("students.dat", "wb") # Open in binary write mode
# ... operations ...
f.close() # Always close!
```

---

### πŸ₯’ 5.5.2 Writing onto a Binary File β€” Pickling!

To write a Python object into a binary file, use **`pickle.dump()`**. You can dump dictionaries, lists, tuples, strings, numbers β€” literally any Python object.

> [!RULE]
> **Syntax:**
> ```
> pickle.dump(object, file_object)
> ```
> - `object` β†’ The Python object to serialize and store
> - `file_object` β†’ File opened in `'wb'` (new) or `'ab'` (append) mode

```python
import pickle

# Writing a single dictionary record
f = open("students.dat", "wb")
student = {"name": "Aman Sharma", "roll": 1, "marks": 95}
pickle.dump(student, f)
f.close()
print("Record written! βœ…")
```

```python
import pickle

# Writing MULTIPLE records β€” one dump per record!
students = [
{"roll": 1, "name": "Aman Sharma", "marks": 95},
{"roll": 2, "name": "Priya Singh", "marks": 88},
{"roll": 3, "name": "Rohan Gupta", "marks": 76},
{"roll": 4, "name": "Sneha Joshi", "marks": 92},
]

f = open("students.dat", "wb")
for student in students:
pickle.dump(student, f) # Each dict dumped separately!
f.close()
print(f"{len(students)} records written! βœ…")
```

```python
import pickle

# Appending a NEW record without losing existing data
f = open("students.dat", "ab") # 'ab' = safe append
new_student = {"roll": 5, "name": "Kavya Reddy", "marks": 98}
pickle.dump(new_student, f)
f.close()
print("New student appended! βœ…")
```

> [!WARNING]
> **Common Mistake:** When writing multiple records with `pickle.dump()` in a loop, each call writes **one independent object**. Don't dump a single giant list if you plan to update individual records later β€” dump them **one by one** so you can read them back one by one with `pickle.load()`. 🚨

> [!TIP]
> **Study Strategy:** Think of `pickle.dump()` like putting items into **individual sealed courier parcels** on a conveyor belt. Each object gets its own package. `pickle.load()` unpacks them one at a time from the other end! πŸ“¦

---

### πŸ“¦ 5.5.3 Reading from a Binary File β€” UnPickling!

To retrieve data from a binary file, use **`pickle.load()`**. Each call reads exactly **one object** that was previously dumped β€” in the same order they were written.

> [!RULE]
> **Syntax:**
> ```
> object = pickle.load(file_object)
> ```
> - `file_object` β†’ File opened in `'rb'` mode
> - Returns the **next reconstructed Python object** from the file
> - Raises **`EOFError`** when no more objects remain (end of file)

```python
import pickle

# Reading a single record
f = open("students.dat", "rb")
student = pickle.load(f)
print(student)
# {'roll': 1, 'name': 'Aman Sharma', 'marks': 95}
f.close()
```

```python
import pickle

# 🌟 Reading ALL records β€” The Standard CBSE Pattern
f = open("students.dat", "rb")
print("All Student Records:")
print("-" * 40)
while True:
try:
student = pickle.load(f)
print(f"Roll: {student['roll']} | Name: {student['name']} | Marks: {student['marks']}")
except EOFError:
break # No more records β€” exit the loop cleanly
f.close()
```

> [!IMPORTANT]
> **Board Exam Hotspot:** The **`EOFError`** (End of File Error) is how Python signals that all objects have been read. The pattern below is **essential to memorize** β€” it appears in virtually every binary file reading/searching question:
> ```python
> while True:
> try:
> record = pickle.load(f)
> # process record
> except EOFError:
> break
> ```

> [!NOTE]
> **Memory Trick:**
> - `dump()` β†’ **D**rop object **U**nder disk's **M**emory **P**rotection (write!)
> - `load()` β†’ **L**ift **O**bject **A**nd **D**eliver back (read!)
>
> Together they're like a **courier service** β€” `dump()` ships the parcel, `load()` delivers it back to you! 🚚

---

### πŸ” 5.5.4 Searching in a Binary File

Searching a binary file means reading records **one by one** and checking each against your criteria. There's no shortcut β€” you must **read β†’ compare β†’ act** for every record.

```mermaid
flowchart TD
A["Open file\nin 'rb' mode"]
B["pickle.load()\nRead one record"]
C{"Record matches\nthe search criteria?"}
D["βœ… Found!\nDisplay / Process it"]
E{"EOFError\nraised?"}
F["❌ Record not found\nPrint message"]
G["Close file"]

A --> B
B --> C
C -->|"Yes β€” Match!"| D
C -->|"No β€” Keep looking"| E
D --> G
E -->|"No β€” more records"| B
E -->|"Yes β€” file ended"| F
F --> G

classDef normalNode fill:none;
classDef elseNode fill:none;
classDef exceptNode fill:none;
classDef tryNode fill:none;

class A normalNode;
class B tryNode;
class C normalNode;
class D elseNode;
class E normalNode;
class F exceptNode;
class G normalNode;
```

```python
import pickle

# Search for a student by roll number
def search_student(roll_no):
found = False
try:
f = open("students.dat", "rb")
while True:
try:
student = pickle.load(f)
if student["roll"] == roll_no:
print("\nβœ… Student Found!")
print(f" Name : {student['name']}")
print(f" Roll : {student['roll']}")
print(f" Marks : {student['marks']}")
found = True
break
except EOFError:
break
f.close()
except FileNotFoundError:
print("Error: File not found!")

if not found:
print(f"❌ No student with roll {roll_no} found.")

search_student(3)
```

```python
import pickle

# Search ALL students scoring above a cutoff (multiple matches)
def toppers(cutoff):
print(f"\nπŸ† Students with marks > {cutoff}:")
print("-" * 35)
count = 0
f = open("students.dat", "rb")
while True:
try:
s = pickle.load(f)
if s["marks"] > cutoff:
print(f" {s['name']} β€” {s['marks']}")
count += 1
except EOFError:
break
f.close()
print(f"\nTotal: {count} student(s)")

toppers(85)
```

> [!TIP]
> **Study Strategy:** Every binary file search follows the **same 3-step skeleton** β€” master this and no question can beat you:
> 1. Open file in `'rb'` mode
> 2. `while True` β†’ `try: pickle.load()` β†’ check condition β†’ `except EOFError: break`
> 3. Close file
>
> The only thing that changes between questions is the **condition inside step 2**! 🎯

---

### ✏️ 5.5.5 Updating in a Binary File

Unlike text files, **you cannot edit a single record inside a pickle binary file directly** β€” changing one record can shift byte positions and corrupt everything after it. The safe and standard CBSE approach is the **Read-All β†’ Modify β†’ Write-All-Back** pattern:

```mermaid
flowchart LR
A["Step 1️⃣\nOpen 'rb'\nRead ALL records into a list"]
B["Step 2️⃣\nFind & modify\nthe target record in the list"]
C["Step 3️⃣\nOpen 'wb'\nOverwrite file with modified list"]
D["βœ… File Updated!"]

A --> B
B --> C
C --> D

classDef tryNode fill:none;
classDef elseNode fill:none;
classDef normalNode fill:none;

class A tryNode;
class B elseNode;
class C tryNode;
class D normalNode;
```

```python
import pickle

def update_marks(roll_no, new_marks):
# ── Step 1: Read ALL records into a Python list ──
records = []
try:
f = open("students.dat", "rb")
while True:
try:
records.append(pickle.load(f))
except EOFError:
break
f.close()
except FileNotFoundError:
print("Error: File not found!")
return

# ── Step 2: Find and modify the target record ────
updated = False
for record in records:
if record["roll"] == roll_no:
print(f"Old marks for {record['name']}: {record['marks']}")
record["marks"] = new_marks
print(f"Updated marks: {record['marks']}")
updated = True
break

if not updated:
print(f"❌ Roll {roll_no} not found!")
return

# ── Step 3: Write ALL records back to file ───────
f = open("students.dat", "wb") # 'wb' overwrites completely
for record in records:
pickle.dump(record, f)
f.close()
print("βœ… Record updated successfully!")

update_marks(2, 95)
```

```python
import pickle

# Deleting a record β€” same Read-Modify-Write pattern!
def delete_student(roll_no):
records = []
f = open("students.dat", "rb")
while True:
try:
rec = pickle.load(f)
if rec["roll"] != roll_no: # Keep ALL except the target
records.append(rec)
except EOFError:
break
f.close()

f = open("students.dat", "wb") # Rewrite without deleted record
for rec in records:
pickle.dump(rec, f)
f.close()
print(f"βœ… Student with roll {roll_no} deleted!")

delete_student(3)
```

> [!IMPORTANT]
> **Board Exam Hotspot:** The update/delete pattern is a **guaranteed exam question**. Always follow:
> 1. `'rb'` β†’ Read all β†’ store in list
> 2. Modify the list in memory
> 3. `'wb'` β†’ Write entire modified list back
>
> Never attempt to overwrite a single record directly inside a pickle file! 🚨

> [!WARNING]
> **Common Mistake:** Students try to use `'rb+'` mode thinking they can edit a specific record in place. **Don't!** Pickle records vary in size β€” overwriting one record shifts all byte positions and corrupts everything after it. Always use the read-all β†’ modify β†’ write-all approach! πŸ”₯

---

### 🧩 Complete Binary File Program β€” All Operations

```python
import pickle

FILENAME = "school.dat"

def create_records():
students = [
{"roll": 1, "name": "Aman Sharma", "marks": 95, "grade": "A+"},
{"roll": 2, "name": "Priya Singh", "marks": 88, "grade": "A"},
{"roll": 3, "name": "Rohan Gupta", "marks": 76, "grade": "B+"},
{"roll": 4, "name": "Sneha Joshi", "marks": 92, "grade": "A+"},
{"roll": 5, "name": "Kavya Reddy", "marks": 65, "grade": "B"},
]
f = open(FILENAME, "wb")
for s in students:
pickle.dump(s, f)
f.close()
print("βœ… Records created!")

def display_all():
f = open(FILENAME, "rb")
print(f"\n{'Roll':<6} {'Name':<20} {'Marks':<8} {'Grade'}")
print("-" * 42)
while True:
try:
s = pickle.load(f)
print(f"{s['roll']:<6} {s['name']:<20} {s['marks']:<8} {s['grade']}")
except EOFError:
break
f.close()

def search_by_name(keyword):
f = open(FILENAME, "rb")
print(f"\nπŸ” Searching for '{keyword}':")
found = False
while True:
try:
s = pickle.load(f)
if keyword.lower() in s["name"].lower():
print(f" β†’ Roll {s['roll']}: {s['name']} | Marks: {s['marks']}")
found = True
except EOFError:
break
f.close()
if not found:
print(" No match found!")

def update_grade(roll, new_grade):
records = []
f = open(FILENAME, "rb")
while True:
try:
records.append(pickle.load(f))
except EOFError:
break
f.close()
for r in records:
if r["roll"] == roll:
r["grade"] = new_grade
f = open(FILENAME, "wb")
for r in records:
pickle.dump(r, f)
f.close()
print(f"βœ… Grade updated for roll {roll}")

# Run all operations
create_records()
display_all()
search_by_name("Singh")
update_grade(3, "A")
display_all()
```

---

## πŸ“Š 5.6 Working with CSV Files

### What is a CSV File?

**CSV** stands for **Comma-Separated Values**. It's a universal, plain-text format for storing **structured tabular data** β€” just like an Excel spreadsheet, but in a simple `.csv` file.

Imagine this Excel table:

| Name | Roll | Marks | Grade |
|------|------|-------|-------|
| Aman | 1 | 95 | A+ |
| Priya | 2 | 88 | A |

In CSV format, that exact same data becomes:
```
Name,Roll,Marks,Grade
Aman,1,95,A+
Priya,2,88,A
```

That's it! Just values separated by commas, one row per line. Beautifully simple. 😍

> [!NOTE]
> **Memory Trick:** CSV = **C**ommas **S**eparating **V**alues! Every row is one line, every column is a comma-separated value. The simplest possible table format β€” yet accepted by Excel, Google Sheets, MySQL, PostgreSQL, and practically every tool on Earth! 🌍

- **Why CSV over plain text files? πŸ“„**
* **Structure** β†’ Data organized in rows and columns β€” not just random lines
* **Universal** β†’ Every tool understands CSV: Excel, databases, Python, R, Java...
* **Human-readable** β†’ Unlike binary, you can open and read it in Notepad
* **Lightweight** β†’ No database software needed β€” just a `.csv` file!
* **Perfect for** β†’ Student records, marks sheets, sales data, inventory, logs

- **Python's `csv` Module 🐍**
* Built-in module β€” no installation needed (`import csv`)
* Handles commas **inside values** automatically using quoting
* `csv.writer` / `csv.reader` β€” list-based read/write
* `csv.DictWriter` / `csv.DictReader` β€” dictionary-based read/write (cleaner!)

> [!RULE]
> **Always import csv at the top:**
> ```python
> import csv
> ```

---

### πŸ”‘ 5.6.1 Opening / Closing CSV Files

CSV files are opened with the same `open()` function β€” with one critical extra argument:

> [!RULE]
> **The Standard CSV Opening Pattern:**
> ```python
> f = open("data.csv", "w", newline='')
> ```
> The **`newline=''`** parameter is essential β€” it prevents Python from adding extra blank lines between rows (especially on Windows)!

- **Modes for CSV files πŸ“**
* `'w'` β†’ Write (creates new / overwrites existing)
* `'r'` β†’ Read (file must exist)
* `'a'` β†’ Append (adds to end, preserves existing data)

```python
import csv

# Writing β€” always newline=''
f = open("marks.csv", "w", newline='')
# ... write operations ...
f.close()

# Reading β€” good practice to include newline='' here too
f = open("marks.csv", "r", newline='')
# ... read operations ...
f.close()

# Best practice β€” with statement (auto-closes, cleaner!)
with open("marks.csv", "w", newline='') as f:
pass # operations here
```

> [!WARNING]
> **Common Mistake:** Forgetting `newline=''` when **writing** CSV on Windows inserts a **blank line between every data row**! This breaks the file structure and trips up every tool trying to read it. Always include `newline=''` β€” no exceptions! 🚨

---

### ✍️ 5.6.2 Writing in CSV Files

Two approaches β€” choose based on whether you're working with lists or dictionaries:

- **✏️ `csv.writer` + `writerow()` / `writerows()`**
* Takes **lists or tuples** β€” each list is one row
* `writerow(list)` β†’ Write a **single row**
* `writerows(list_of_lists)` β†’ Write **all rows** at once β€” efficient!

- **πŸ“’ `csv.DictWriter` + `writeheader()` + `writerow()`**
* Takes **dictionaries** β€” keys become column headers automatically
* `writeheader()` β†’ Write the first row as column names
* `writerow(dict)` β†’ Write one dict as one data row

#### Method 1 β€” `csv.writer` (List-based)

```python
import csv

# writerow() β€” one row at a time
with open("students.csv", "w", newline='') as f:
writer = csv.writer(f)

writer.writerow(["Roll", "Name", "Marks", "Grade"]) # Header
writer.writerow([1, "Aman Sharma", 95, "A+"])
writer.writerow([2, "Priya Singh", 88, "A"])
writer.writerow([3, "Rohan Gupta", 76, "B+"])

print("CSV written! βœ…")
# File (students.csv):
# Roll,Name,Marks,Grade
# 1,Aman Sharma,95,A+
# 2,Priya Singh,88,A
# 3,Rohan Gupta,76,B+
```

```python
import csv

# writerows() β€” write ALL rows in one efficient call!
with open("students.csv", "w", newline='') as f:
writer = csv.writer(f)

header = ["Roll", "Name", "Marks", "Grade"]
data = [
[1, "Aman Sharma", 95, "A+"],
[2, "Priya Singh", 88, "A"],
[3, "Rohan Gupta", 76, "B+"],
[4, "Sneha Joshi", 92, "A+"],
[5, "Kavya Reddy", 65, "B"],
]
writer.writerow(header) # Header first
writer.writerows(data) # All data in one go!

print("All records written with writerows()! βœ…")
```

#### Method 2 β€” `csv.DictWriter` (Dictionary-based)

```python
import csv

# DictWriter β€” cleaner, safer for complex data
with open("students.csv", "w", newline='') as f:

fields = ["Roll", "Name", "Marks", "Grade"]
writer = csv.DictWriter(f, fieldnames=fields)

writer.writeheader() # Writes: Roll,Name,Marks,Grade

students = [
{"Roll": 1, "Name": "Aman Sharma", "Marks": 95, "Grade": "A+"},
{"Roll": 2, "Name": "Priya Singh", "Marks": 88, "Grade": "A"},
{"Roll": 3, "Name": "Rohan Gupta", "Marks": 76, "Grade": "B+"},
]
for s in students:
writer.writerow(s)

print("DictWriter done! βœ…")
```

> [!IMPORTANT]
> **Board Exam Hotspot β€” `write` methods summary:**
> | Method | Used With | Writes |
> |--------|-----------|--------|
> | `writerow(list)` | `csv.writer` | One row as a list |
> | `writerows(list_of_lists)` | `csv.writer` | Multiple rows at once |
> | `writeheader()` | `csv.DictWriter` only | Column names as first row |
> | `writerow(dict)` | `csv.DictWriter` | One row as a dictionary |

---

### πŸ“– 5.6.3 Reading in CSV Files

Reading mirrors writing β€” two clean approaches:

- πŸ“‹ **`csv.reader`** β€” Reads each row as a **list of strings**
- πŸ“’ **`csv.DictReader`** β€” Reads each row as a **dictionary** (first row = keys)

#### Method 1 β€” `csv.reader` (List-based)

```python
import csv

# Basic reading β€” each row is a list
with open("students.csv", "r", newline='') as f:
reader = csv.reader(f)
for row in reader:
print(row)
# Output:
# ['Roll', 'Name', 'Marks', 'Grade'] ← header row (a list!)
# ['1', 'Aman Sharma', '95', 'A+'] ← all values are STRINGS!
# ['2', 'Priya Singh', '88', 'A']
```

```python
import csv

# Skip header, then process data rows
with open("students.csv", "r", newline='') as f:
reader = csv.reader(f)

header = next(reader) # Read and skip the header row
print(f"Columns: {header}")

for row in reader:
roll = int(row[0]) # ← Convert string to int!
name = row[1]
marks = int(row[2]) # ← CSV gives strings β€” always convert!
grade = row[3]
print(f"Roll {roll}: {name} scored {marks} marks ({grade})")
```

#### Method 2 β€” `csv.DictReader` (Dictionary-based β€” Recommended!)

```python
import csv

# DictReader β€” access columns by name, not index
with open("students.csv", "r", newline='') as f:
reader = csv.DictReader(f) # First row auto-becomes dict keys!

for row in reader:
# Access by column name β€” much cleaner than row[0], row[2]!
print(f"{row['Name']} β†’ Marks: {row['Marks']}, Grade: {row['Grade']}")
```

> [!WARNING]
> **Common Mistake:** `csv.reader` reads **everything as strings** β€” even numbers! `95` becomes `'95'`. Always convert:
> ```python
> marks = int(row[2]) # βœ… '95' β†’ 95
> price = float(row[3]) # βœ… '45.5' β†’ 45.5
> ```
> Forgetting this breaks any arithmetic and causes `TypeError`! 🚨

> [!NOTE]
> **Memory Trick:**
> - `csv.writer` / `csv.reader` β†’ Work with **lists** (access by position: `row[0]`, `row[1]`)
> - `csv.DictWriter` / `csv.DictReader` β†’ Work with **dicts** (access by name: `row['Name']`, `row['Marks']`)
>
> The **Dict** variants are cleaner, safer, and far more readable. Prefer them whenever possible! πŸ“’

---

### ✍️ CSV Write Operation β€” Visual Guide

```mermaid
flowchart LR
A["🐍 Python Data\nLists / Dicts"]
B["open() with\nnewline=''"]
C["csv.writer\nor DictWriter"]
D["writerow()\nwriterows()\nwriteheader()"]
E["πŸ’Ύ CSV File\nstudents.csv"]

A --> B --> C --> D --> E

classDef dataNode fill:none;
classDef fileNode fill:none;
class A,E dataNode;
class B,C,D fileNode;
```
### πŸ“– CSV Read Operation β€” Visual Guide

```mermaid
flowchart LR
E["πŸ’Ύ CSV File\nstudents.csv"]
F["open() with\nnewline=''"]
G["csv.reader\nor DictReader"]
H["for row in reader\nProcess each row"]
I["βœ… Restored Data\n(convert types!)"]

E --> F --> G --> H --> I

classDef dataNode fill:none;
classDef fileNode fill:none;
class E,I dataNode;
class F,G,H fileNode;

```
---

### 🧩 Complete CSV Program β€” All Operations

```python
import csv

FILENAME = "library.csv"
FIELDS = ["BookID", "Title", "Author", "Price", "Qty"]

def create_library():
"""Write initial records"""
books = [
[101, "Python Basics", "Guido Van", 450, 15],
[102, "Data Structures", "Mark Allen", 620, 8],
[103, "Computer Networks", "Forouzan", 780, 12],
[104, "DBMS Concepts", "Korth", 590, 5],
[105, "Artificial Intelligence","Russell", 850, 10],
]
with open(FILENAME, "w", newline='') as f:
writer = csv.writer(f)
writer.writerow(FIELDS) # Header
writer.writerows(books) # All data
print("βœ… Library CSV created!")

def display_all():
"""Read and display all books"""
with open(FILENAME, "r", newline='') as f:
reader = csv.DictReader(f)
print(f"\n{'ID':<6} {'Title':<28} {'Author':<16} {'Price':>7} {'Qty':>5}")
print("-" * 65)
for row in reader:
print(f"{row['BookID']:<6} {row['Title']:<28} {row['Author']:<16} β‚Ή{row['Price']:>5} {row['Qty']:>5}")

def search_by_author(name):
"""Search books by author name"""
print(f"\nπŸ“š Books by '{name}':")
found = False
with open(FILENAME, "r", newline='') as f:
reader = csv.DictReader(f)
for row in reader:
if name.lower() in row["Author"].lower():
print(f" β†’ {row['Title']} (β‚Ή{row['Price']})")
found = True
if not found:
print(" No books found!")

def add_book(bid, title, author, price, qty):
"""Append a new book"""
with open(FILENAME, "a", newline='') as f:
writer = csv.writer(f)
writer.writerow([bid, title, author, price, qty])
print(f"βœ… '{title}' added to library!")

# Run all operations
create_library()
display_all()
search_by_author("Korth")
add_book(106, "Operating Systems", "Silberschatz", 710, 7)
display_all()
```

---

## πŸ†š Binary File vs CSV File β€” Side-by-Side

> [!IMPORTANT]
> **Board Exam Hotspot β€” The Must-Know Comparison Table:**
>
> | Feature | Binary File (`pickle`) | CSV File (`csv`) |
> |---------|----------------------|-----------------|
> | Module | `pickle` | `csv` |
> | Human-readable? | ❌ No | βœ… Yes |
> | Stores Python objects? | βœ… Any object | ⚠️ Strings only |
> | Opens in Excel? | ❌ No | βœ… Yes |
> | File mode | `'rb'`, `'wb'`, `'ab'` | `'r'`, `'w'`, `'a'` |
> | Write function | `pickle.dump()` | `writerow()` / `writerows()` |
> | Read function | `pickle.load()` | `for row in reader:` |
> | End of file detection | `EOFError` exception | Loop ends naturally |
> | Type preservation | βœ… int, list, dict intact | ❌ Everything becomes string |
> | Special parameter | None | `newline=''` in `open()` |

---

## πŸ† Rapid Revision β€” Board Exam Ready!

> [!TIP]
> **Study Strategy β€” 6 Must-Practise CBSE Questions:**
> 1. πŸ–ŠοΈ "What is pickling? Write a program to write and read a dictionary using pickle"
> 2. πŸ–ŠοΈ "Write a program to search a record in a binary file by a given field"
> 3. πŸ–ŠοΈ "Write a program to update/modify a record in a binary file"
> 4. πŸ–ŠοΈ "Difference between text file, binary file, and CSV file"
> 5. πŸ–ŠοΈ "Write a program to write data into a CSV file using csv.writer"
> 6. πŸ–ŠοΈ "Why is `newline=''` used when opening a CSV file in Python?"

> [!WARNING]
> **Common Mistakes β€” Final Exam Checklist:**
> 1. ❌ Forgetting `import pickle` or `import csv`
> 2. ❌ Opening binary files in text mode (`'w'` instead of `'wb'`)
> 3. ❌ Not handling `EOFError` in binary file reading loops
> 4. ❌ Forgetting `newline=''` in CSV `open()` β€” causes blank rows
> 5. ❌ Not converting CSV string values to `int`/`float` before arithmetic
> 6. ❌ Trying to update a binary file record in-place (using `'rb+'`) instead of the read-all β†’ modify β†’ write-all pattern

```python
# ✏️ Bonus Program: Export Binary File β†’ CSV File
# The ultimate combo question β€” often seen in CBSE practicals!
import pickle, csv

# Step 1: Read all records from binary file
records = []
with open("students.dat", "rb") as bf:
while True:
try:
records.append(pickle.load(bf))
except EOFError:
break

# Step 2: Write all records to CSV
with open("students.csv", "w", newline='') as cf:
if records:
writer = csv.DictWriter(cf, fieldnames=records[0].keys())
writer.writeheader()
writer.writerows(records)

print(f"βœ… Exported {len(records)} records from binary (.dat) to CSV!")
```
πŸ“

Test Your Knowledge

Practice real board exam questions for this chapter.

View Solved Board Questions