如何在Python中以相反的顺序读取CSV文件?

Sir*_*irC 9 python csv

我知道如何为TXT文件执行此操作,但现在我在为CSV文件执行此操作时遇到了一些麻烦.

如何在Python中从底部读取CSV文件?

Mik*_*one 21

与文本文件几乎相同:将整个内容读入列表然后返回:

import csv
with open('test.csv', 'r') as textfile:
    for row in reversed(list(csv.reader(textfile))):
        print ', '.join(row)
Run Code Online (Sandbox Code Playgroud)

如果你想得到花哨的话,你可以编写很多代码来读取从文件末尾开始并向后工作的块,一次发出一行,然后将其提供给csv.reader,但这只能用于一个文件,可以寻找,即磁盘文件,但不是标准输入.


我们中的一些人的文件不适合内存,任何人都可以提供一个不需要将整个文件存储在内存中的解决方案吗?

这有点棘手.幸运的是,所有csv.reader期望的是一个类似迭代器的对象,每次调用返回一个字符串(行)next().所以我们抓住Darius Bacon以" 最有效的方式在python中搜索文件的最后x行 "中提供的技术来向后读取文件的行,而不必拉入整个文件:

import os

def reversed_lines(file):
    "Generate the lines of file in reverse order."
    part = ''
    for block in reversed_blocks(file):
        for c in reversed(block):
            if c == '\n' and part:
                yield part[::-1]
                part = ''
            part += c
    if part: yield part[::-1]

def reversed_blocks(file, blocksize=4096):
    "Generate blocks of file's contents in reverse order."
    file.seek(0, os.SEEK_END)
    here = file.tell()
    while 0 < here:
        delta = min(blocksize, here)
        here -= delta
        file.seek(here, os.SEEK_SET)
        yield file.read(delta)
Run Code Online (Sandbox Code Playgroud)

并提供reversed_lines代码以它们到达之前反转行csv.reader,从而无需reversedlist:

import csv
with open('test.csv', 'r') as textfile:
    for row in csv.reader(reversed_lines(textfile)):
        print ', '.join(row)
Run Code Online (Sandbox Code Playgroud)

有一个更可能的Pythonic解决方案,它不需要在内存中逐个字符地反转块(提示:只需获取一个索引列表,其中块中有行结束,反转它,并使用它切片块),并用来chainitertools连续块中的线簇粘合在一起,但这留给读者练习.


值得注意的是,如果CSV文件中的列不包含换行符,则上述的reversed_lines()惯用法才有效.

AARGH!总有一些东西.幸运的是,解决这个问题并不算太糟糕:

def reversed_lines(file):
    "Generate the lines of file in reverse order."
    part = ''
    quoting = False
    for block in reversed_blocks(file):
        for c in reversed(block):
            if c == '"':
                quoting = not quoting
            elif c == '\n' and part and not quoting:
                yield part[::-1]
                part = ''
            part += c
    if part: yield part[::-1]
Run Code Online (Sandbox Code Playgroud)

当然,如果您的CSV方言不使用,则需要更改引号字符".