Binary file handling in Python

Viewed 405

I am trying to write & display the id ,name and salary of 3 employees from .dat file using pickle methods in Python but while displaying I am able to see only 1 employee details the rest are not coming. Please suggest as where the problem is in the below code.

import pickle

class Emp:
    def __init__(self, id, name, sal):
        self.id = id
        self.name = name
        self.sal = sal
    def display(self):
        print('{} {} {}'.format(self.id, self.name, self.sal))
    
n = int(input('How many employees?'))
for i in range(n):
    id = int(input('Enter the id:'))
    name = input('Enter name:')
    sal = float(input('Enter salary: '))
    f = open('emp.dat', 'wb')    
    e = Emp(id, name, sal)
    pickle.dump(e, f)
f = open('emp.dat', 'rb')
print('Employee details: ')
obj = pickle.load(f)
obj.display()

Example run:

INPUT: 
How many employees?2
Enter the id:12
Enter name:john
Enter salary: 89000
Enter the id:34
Enter name:mark
Enter salary: 83111
obj.display()
OUTPUT:
Employee details: 
12 john 89000.0
2 Answers

You're opening the file using wb (write binary). The w mode truncates (empties) the file upon opening, so you're effectively overwriting the records as you go.

Instead use ab (append binary) (and as @Maaz mentioned, use the with statement).

Furthermore, when reading data from the file, you will need to loop for as long as you can to read all of the records. (Happily pickle is a concatenation-tolerant format, so you can just read and read.)

import pickle


class Emp:
    def __init__(self, id, name, sal):
        self.id = id
        self.name = name
        self.sal = sal

    def display(self):
        print("{} {} {}".format(self.id, self.name, self.sal))


n = int(input("How many employees?"))
for i in range(n):
    id = int(input("Enter the id:"))
    name = input("Enter name:")
    sal = float(input("Enter salary: "))
    with open("emp.dat", "ab") as f:
        e = Emp(id, name, sal)
        pickle.dump(e, f)

with open("emp.dat", "rb") as f:
    while True:
        try:
            obj = pickle.load(f)
        except EOFError:  # Nothing to read
            break
        print("Employee details: ")
        obj.display()

Alternately (as discussed in comments), if you want to clear the file but write a number of new records, open the file in w mode only once, then write into it multiple times.

with open("emp.dat", "wb") as f:
    for i in range(n):
        id = int(input("Enter the id:"))
        name = input("Enter name:")
        sal = float(input("Enter salary: "))
        e = Emp(id, name, sal)
        pickle.dump(e, f)
import pickle

class Emp:
    def __init__(self, id, name, sal):
        self.id = id
        self.name = name
        self.sal = sal
    def display(self):
        print('{} {} {}'.format(self.id, self.name, self.sal))

n = int(input('How many employees?'))
emps = []
for i in range(n):
    id = int(input('Enter the id:'))
    name = input('Enter name:')
    sal = float(input('Enter salary: '))
    e = Emp(id, name, sal)
    emps.append(e)
with open('emp.dat', 'wb') as f:
    pickle.dump(emps, f)
with open('emp.dat', 'rb') as f:
    print('Employee details: ')
    objs = pickle.load(f)
    for obj in objs:
        obj.display()

Example run:

How many employees?2
Enter the id:1
Enter name:a
Enter salary: 10
Enter the id:2
Enter name:b
Enter salary: 20
Employee details: 
1 a 10.0
2 b 20.0
Related