Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get CSV reader to read a memory file?

I'm trying to fetch an entire file into memory (done - using StringIO) - but these objects don't really behave exactly like 'real' files as far as I can see - I get the whole contents, or I can read a line at a time, but I can't work out how to apply this pattern:

import csv 
with open(#MYMEMORYFILE_HERE#, 'rb') as csvfile:
        spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|')
        for row in spamreader:

Is there a way of treating a memoryfile just like an on-disk file , so I can use the nicer idioms above ?

Python 2.7.4 (default, Apr 19 2013, 18:28:01) 

EDIT: Thanks for the answers on this - I think I have narrowed down what was confusing me...but I still have an issue here, the following doesn't output anything? I suspect flushing ?

from csv import reader, writer
import StringIO

memfile=StringIO.StringIO()
spamwriter = writer(memfile)
spamwriter.writerow(['Spam'] * 5 + ['Baked Beans'])
spamwriter.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam'])
spamreader=reader(memfile)
for row in spamreader:
        print ', '.join(row)
memfile.close()

EDIT#2: But I'm barking up the wrong tree I think: I couldn't get the on-disk version of this to work either ('IOError: File not open for reading' - when I call the read on the already open file...) EDIT#3: abandoned the StringIO (no real need for it) - used splitlines as per the answer.

I'll leave the code and comments here - in case it's useful. (even though it is a cul-de-sac).

like image 338
monojohnny Avatar asked Jul 20 '13 22:07

monojohnny


2 Answers

If you want to read a whole file into memory, and it's text, you don't need to open a StringIO object. Just read it as a string!

with open(filename, 'r') as file:
    in_memory_file = file.read()

Then you can use splitlines to iterate over it the way you would iterate over an open text file.

spamreader = csv.reader(in_memory_file.splitlines(), delimiter=' ', quotechar='|')
for row in spamreader:
    pass
like image 131
llb Avatar answered Sep 30 '22 17:09

llb


There is no need to open the StringIO object, it is already an open file object:

spamreader = csv.reader(MYMEMORYFILE_HERE, delimiter=' ', quotechar='|')

All that csv.reader() needs is an iterable object. A StringIO object fits that requirement.

Demo:

>>> from StringIO import StringIO
>>> data = StringIO('1,2,3\n4,5,6\n')
>>> import csv
>>> for row in csv.reader(data):
...     print row
... 
['1', '2', '3']
['4', '5', '6']

As for your own StringIO.StringIO test; you wrote to a file object but neglected to seek back to the start; no data will be read as the file pointer is still at the end. Seek back:

memfile.seek(0)
spamreader=reader(memfile)
like image 30
Martijn Pieters Avatar answered Sep 30 '22 18:09

Martijn Pieters