Reading csv file

Peter Otten __peter__ at web.de
Tue Dec 17 11:51:04 CET 2013


Igor Korot wrote:

> Hi, guys,
> 
> On Tue, Dec 17, 2013 at 12:55 AM, Peter Otten <__peter__ at web.de> wrote:
>> Peter Otten wrote:
>>
>>> You are still reading the complete csv file. Assuming
>>>
>>> (1) the first row of the csv contains the column names
>>> (2) you want to skip the first five rows of data
> 
> Looking at the Peter's reply I realized I missed very important piece:
> 
> The first row may or may not contain column names.
> If it does not, the first row will just contain some text, i.e. "abc"
> and the column names will be located on the row 6.
> 
> I know if does complicate things but I am deeply sorry.
> The csv file is generated by some program run and I guess depending on
> the switches passed to
> that program it either creates the header in the csv (report name,
> time slice it ran at, user it ran under
> and some other info.
> Or it can be run without such switch and then it generates a normal csv.
> 
> The report it generates is huge: it has about 30+ fields and I need to
> read this report, parse it and
> push accordingly to the database of mySQL.
> 
> Thank you for any suggestions and sorry for not posting complete task.

Try the following (without the mock-ups of course):


$ cat csv_skip_header.py
import csv
import sys
from contextlib import contextmanager

filename = "ignored"

@contextmanager
def open(*args):
    "mock-up, replace with open() built-in"
    from StringIO import StringIO
    lines = range(10)
    if len(sys.argv) > 1 and sys.argv[1] == "--skip":
        lines[0] = "skipped"
        lines[6] = "field1-from-line6,field2-from-line6"
    else:
        lines[0] = "field1-from-line1,field2-from-line1"
    yield StringIO("\r\n".join(map(str, lines)))

def is_arbitrary_text(fieldnames):
    "mock-up, replace with the actual check"
    return "skipped" in fieldnames

with open(filename, "rb") as f:
    reader = csv.DictReader(f)
    if is_arbitrary_text(reader.fieldnames):
        for _ in range(5):
            next(reader, None)
        reader._fieldnames = None # underscore necessary,
                                  # fieldnames setter doesn't work
        reader.fieldnames # used for its side-effect
    for row in reader:
        print row
$ python csv_skip_header.py 
{'field2-from-line1': None, 'field1-from-line1': '1'}
{'field2-from-line1': None, 'field1-from-line1': '2'}
{'field2-from-line1': None, 'field1-from-line1': '3'}
{'field2-from-line1': None, 'field1-from-line1': '4'}
{'field2-from-line1': None, 'field1-from-line1': '5'}
{'field2-from-line1': None, 'field1-from-line1': '6'}
{'field2-from-line1': None, 'field1-from-line1': '7'}
{'field2-from-line1': None, 'field1-from-line1': '8'}
{'field2-from-line1': None, 'field1-from-line1': '9'}
$ python csv_skip_header.py --skip
{'field1-from-line6': '7', 'field2-from-line6': None}
{'field1-from-line6': '8', 'field2-from-line6': None}
{'field1-from-line6': '9', 'field2-from-line6': None}

You may find the following a bit cleaner:

with open(filename, "rb") as f:
    reader = csv.reader(f)
    fieldnames = next(reader)
    if is_arbitrary_text(fieldnames):
        for _ in range(5):
            next(reader, None)
        fieldnames = None
    reader = csv.DictReader(f, fieldnames=fieldnames)
    for row in reader:
        print row

Or you do the skipping on the file (only if the rows don't have embedded 
newlines).




More information about the Python-list mailing list