[英]Python csv.DictReader - how to reverse output?
我試圖扭轉文件的讀取方式。 我正在使用DictReader,因為我想要一個字典中的內容。 我想讀取文件中的第一行並將其用於Keys,然后反向解析文件(從下到上),類似於linux“tac”命令。 是否有捷徑可尋? 下面是我的代碼,將文件讀入字典並將其寫入文件...
reader = csv.DictReader(open(file_to_parse, 'r'), delimiter=',', quotechar='"')
for line in reader:
# ...
這段代碼可以正常處理文件,但是我需要它從最后讀取文件。
換句話說,我希望它能夠讀取文件:
fruit, vegetables, cars
orange, carrot, ford
apple, celery, chevy
grape, corn, chrysler
並能夠讓它返回:
{' cars': ' chrysler', ' vegetables': ' corn', 'fruit': 'grape'}
{' cars': ' chevy', ' vegetables': ' celery', 'fruit': 'apple'}
{' cars': ' ford', ' vegetables': ' carrot', 'fruit': 'orange'}
代替:
{' cars': ' ford', ' vegetables': ' carrot', 'fruit': 'orange'}
{' cars': ' chevy', ' vegetables': ' celery', 'fruit': 'apple'}
{' cars': ' chrysler', ' vegetables': ' corn', 'fruit': 'grape'}
您必須將整個 CSV文件讀入內存; 你可以通過調用reader對象上的list()
來實現:
with open(file_to_parse, 'rb') as inf:
reader = csv.DictReader(inf, skipinitialspace=True)
rows = list(reader)
for row in reversed(rows):
請注意,我在此處使用該文件作為上下文管理器以確保文件已關閉。 您還希望以二進制模式打開文件(將換行處理留給csv
模塊)。 您傳遞給DictReader()
的其余配置是默認值,因此我省略了它們。
我將skipinitialspace
設置為True,從您的示例輸入和輸出判斷,您的分隔符后面有空格; 該選項刪除了這些。
csv.DictReader()
對象負責將第一行作為鍵讀取。
演示:
>>> import csv
>>> sample = '''\
... fruit, vegetables, cars
... orange, carrot, ford
... apple, celery, chevy
... grape, corn, chrysler
... '''.splitlines()
>>> reader = csv.DictReader(sample, skipinitialspace=True)
>>> rows = list(reader)
>>> for row in reversed(rows):
... print row
...
{'cars': 'chrysler', 'vegetables': 'corn', 'fruit': 'grape'}
{'cars': 'chevy', 'vegetables': 'celery', 'fruit': 'apple'}
{'cars': 'ford', 'vegetables': 'carrot', 'fruit': 'orange'}
讀到列表並反轉:
lines = [x for x in reader]
for line in lines[::-1]:
print line
{' cars': ' chrysler', ' vegetables': ' corn', 'fruit': 'grape'}
{' cars': ' chevy', ' vegetables': ' celery', 'fruit': 'apple'}
{' cars': ' ford', ' vegetables': ' carrot', 'fruit': 'orange'}
或者正如Martijn Pieters所說:
for line in reversed(list(reader)):
您實際上不必將整個文件讀入內存。
csv.DictReader
實際上並不需要一個文件,只是一個可迭代的字符串。*
並且您可以以平均線性時間以相反的順序讀取文本文件,其中空間不變,而且開銷不會太大 。 這不是微不足道的,但並不難:
def reverse_lines(*args, **kwargs):
with open(*args, **kwargs) as f:
buf = ''
f.seek(0, io.SEEK_END)
while f.tell():
try:
f.seek(-1024, io.SEEK_CUR)
except OSError:
bufsize = f.tell()
f.seek(0, io.SEEK_SET)
newbuf = f.read(bufsize)
f.seek(0, io.SEEK_SET)
else:
newbuf = f.read(1024)
f.seek(-1024, io.SEEK_CUR)
buf = newbuf + buf
lines = buf.split('\n')
buf = lines.pop(0)
yield from reversed(lines)
yield buf
這沒有經過嚴格的測試,它剝離了換行符(這對於csv.DictReader
來說很好,但一般來說不是很好),並且它沒有針對不尋常但可能的邊緣情況進行優化(例如,對於非常長的行,它將是二次),它需要Python 3.3,並且文件不會消失,直到你關閉/釋放迭代器(它可能應該是一個上下文管理器,所以你可以處理它) - 但如果你真的想要這個,我是願意打賭你可以在ActiveState上找到一個配方或在PyPI上找到一個沒有這些問題的分配。
無論如何,對於一個中等大小的文件,我懷疑在幾乎任何現實生活中的文件系統上實際上都要以正向順序將整個內容讀入內存然后反向迭代列表。 但是對於一個非常大的文件(特別是一個你甚至無法適應內存的文件),這個解決方案顯然要好得多。
通過快速測試(請參閱http://pastebin.com/Nst6WFwV獲取代碼),在我的計算機上,基本細分是:
當然,細節將取決於有關您的計算機的大量事實。 可能並非巧合的是,500M 72-char的ASCII線占據了我機器上近一半的物理RAM。 但是使用硬盤而不是SSD你可能會看到對reverse_lines
更多懲罰(因為隨機讀取與連續讀取相比會慢很多,而且通常磁盤會更重要)。 而你的平台的malloc和VM行為,甚至地點問題(在讀取它之后幾乎立即解析一條線而不是在它被換出並重新進入......之后)可能會有所不同。 等等。
無論如何,教訓是,如果你不期望至少有數百萬行(或者在資源有限的機器上可能少一點),甚至不要考慮這個問題; 保持簡單。
*正如Martijn Pieters在評論中指出的那樣,如果你沒有使用顯式fieldnames
, DictReader
需要一個可迭代的字符串,其中第一行是標題 。 但是你可以通過分別用csv.reader
讀取第一行並將其作為fieldnames
傳遞來解決這個問題,甚至可以通過itertools.chain
來解決這個問題。來自前向讀取的所有第一行除了后向讀取的最后csv.reader
行之外。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.