让csv.reader知道何时到达最后一行

10 投票
7 回答
34419 浏览
提问于 2025-04-15 12:08

显然,在某些地方的CSV输出实现中,当最后一行的字段为空时,会把字段分隔符从右边截断,只在文件的最后一行发生这种情况。

下面是一个示例输入的CSV文件,其中字段'c'和'd'是可为空的:

a|b|c|d
1|2||
1|2|3|4
3|4||
2|3

在下面这样的脚本中,我怎么才能知道我是否在最后一行,以便我可以正确处理它呢?

import csv

reader = csv.reader(open('somefile.csv'), delimiter='|', quotechar=None)

header = reader.next()

for line_num, row in enumerate(reader):
    assert len(row) == len(header)
    ....

7 个回答

3

如果你希望每一行都有固定数量的列,那你就需要做好防范,考虑到以下两种情况:

(1) 任何一行可能会短一些——比如说,某些写入工具(像 SQL Server 或 Query Analyzer,我记得没错的话)可能会随机省略掉结尾的空值;用户也可能会用文本编辑器修改文件,甚至留下空行。

(2) 任何一行可能会长一些——比如说,逗号没有正确地加引号。

你不需要使用什么复杂的技巧。只需要在读取每一行的时候,做一个简单的判断:

for row in csv.reader(...):
    ncols = len(row)
    if ncols != expected_cols:
        appropriate_action()
6

我知道这个问题已经问过很久了,但我想出了一个不同的答案。这个 reader 对象在你遍历它的时候,已经会自动增加 line_num 这个属性。所以我一开始用 row_count 得到总行数,然后再把它和 line_num 进行比较。

import csv

def row_count(filename):
    with open(filename) as in_file:
        return sum(1 for _ in in_file)

in_filename = 'somefile.csv'
reader = csv.reader(open(in_filename), delimiter='|')

last_line_number = row_count(in_filename)
for row in reader:
    if last_line_number == reader.line_num:
        print "It is the last line: %s" % row
16

基本上,你只有在用完之后才知道自己已经用完了。所以你可以把 reader 这个迭代器包裹起来,比如这样:

def isLast(itr):
  old = itr.next()
  for new in itr:
    yield False, old
    old = new
  yield True, old

然后把你的代码改成:

for line_num, (is_last, row) in enumerate(isLast(reader)):
    if not is_last: assert len(row) == len(header)

等等。

撰写回答