TangoAlee
TangoAlee

Reputation: 1380

Read/Write to same file using csv.dictreader python

I have the following code which takes a csv file and chops out only the columns that match the fields list.

def mi_columnDeleter(filenameWithPath):
    #The fields I want
    fields = ["Part Number", "Full MI", "Accepts", "Attempts"]

    #Open the file
    infile = codecs.open(filenameWithPath, 'rb')    
    #hook the DictReader
    r = csv.DictReader(infile)
    #error occurs here because I have it before 'r' below
    infile.close()
    #open the same file
    outfile = open(filenameWithPath, "wb")
    w = csv.DictWriter(outfile, fields, extrasaction="ignore")
    w.writeheader()
    for row in r:
        w.writerow(row)
    outfile.close()

I get the following I/O error I/O operation on closed file because I have infile.close() before I use r.

My question is there a way to read in the csv data - chop it down to the correct columns - then save it back to the same file?

I know there are workarounds but I'm sure that python should be able to do this.

Upvotes: 1

Views: 1818

Answers (1)

Padraic Cunningham
Padraic Cunningham

Reputation: 180481

If you want to reopen the same file for writing you need to store the rows in a list first, you cannot close the file and then try to iterate over the lines:

 r = csv.DictReader(infile)
 r = list(r)
 ..........

A better approach would be writing to a tempfile, using shutil.move to replace the original file after updating:

from shutil import move
from tempfile import NamedTemporaryFile
import csv
import os

def mi_columnDeleter(filenameWithPath):
    fields = ["Part Number", "Full MI", "Accepts", "Attempts"]
    with codecs.open(filenameWithPath, 'rb') as f, NamedTemporaryFile("w",dir=".", delete=False) as temp:
        r = csv.DictReader(f)
        w = csv.DictWriter(temp, fields, extrasaction="ignore")
        w.writeheader()
        w.writerows(r)
    move(temp.name,filenameWithPath)

Using as input:

a,b,c
1,2,3
4,5,6

and fields defined as fields = ["a","c"] would output:

a,c
1,3
4,6

You can also simply call writerows passing in the reader object with using the for loop in your own code.

Upvotes: 2

Related Questions