TXTファイルに対してそれを行う方法を知っていますが、CSVファイルに対してそれを行うのに問題があります。
PythonでCSVファイルを下から読み取るにはどうすればよいですか?
テキストファイルの場合とほぼ同じ方法です。すべてをリストに読み込んでから、逆方向に移動します。
import csv
with open('test.csv', 'r') as textfile:
for row in reversed(list(csv.reader(textfile))):
print ', '.join(row)
ファンシーになりたい場合は、ファイルの最後から逆方向にブロックを読み取り、一度に1行ずつ出力し、それをにフィードする多くのコードを記述できますが、これは次のファイルでcsv.reader
のみ機能します。シークできます。つまり、ディスクファイルですが、標準入力ではありません。
私たちの中にはメモリに収まらないファイルを持っている人もいますが、ファイル全体をメモリに保存する必要のないソリューションを誰かが思いつくことができますか?
それは少しトリッキーです。幸いなことに、すべてのcsv.reader
期待は、への呼び出しごとに文字列(行)を返すイテレータのようなオブジェクトですnext()
。そこで、「 Pythonでファイルの最後のx行を検索する最も効率的な方法」で示したDarius Baconの手法を利用して、ファイル全体をプルすることなく、ファイルの行を逆方向に読み取ります。
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)
コードにフィードして、行が到達する前reversed_lines
に行を逆にし、との必要性を排除します。csv.reader
reversed
list
import csv
with open('test.csv', 'r') as textfile:
for row in csv.reader(reversed_lines(textfile)):
print ', '.join(row)
よりPythonicな解決策があります。これは、メモリ内のブロックを文字ごとに反転する必要がありません(ヒント:ブロック内に行末があるインデックスのリストを取得し、それを反転して、次のように使用します。ブロックをスライスします)、およびを使用chain
してitertools
、連続するブロックからのラインクラスターを接着しますが、それは読者の練習問題として残されています。
上記のreversed_lines()イディオムは、CSVファイルの列に改行が含まれていない場合にのみ機能することに注意してください。
ああ!常に何かがあります。幸いなことに、これを修正するのはそれほど悪くありません。
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]
もちろん、CSV方言でを使用しない場合は、引用文字を変更する必要があります"
。
@mike-desimoneの答えに基づいて構築します。これは、Pythonファイルオブジェクトと同じ構造を提供するが、行ごとに逆に読み取られるソリューションです。
import os
class ReversedFile(object):
def __init__(self, f, mode='r'):
"""
Wraps a file object with methods that make it be read in reverse line-by-line
if ``f`` is a filename opens a new file object
"""
if mode != 'r':
raise ValueError("ReversedFile only supports read mode (mode='r')")
if not type(f) == file:
# likely a filename
f = open(f)
self.file = f
self.lines = self._reversed_lines()
def _reversed_lines(self):
"Generate the lines of file in reverse order."
part = ''
for block in self._reversed_blocks():
for c in reversed(block):
if c == '\n' and part:
yield part[::-1]
part = ''
part += c
if part: yield part[::-1]
def _reversed_blocks(self, blocksize=4096):
"Generate blocks of file's contents in reverse order."
file = self.file
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)
def __getattribute__(self, name):
"""
Allows for the underlying file attributes to come through
"""
try:
# ReversedFile attribute
return super(ReversedFile, self).__getattribute__(name)
except AttributeError:
# self.file attribute
return getattr(self.file, name)
def __iter__(self):
"""
Creates iterator
"""
return self
def seek(self):
raise NotImplementedError('ReversedFile does not support seek')
def next(self):
"""
Next item in the sequence
"""
return self.lines.next()
def read(self):
"""
Returns the entire contents of the file reversed line by line
"""
contents = ''
for line in self:
contents += line
return contents
def readline(self):
"""
Returns the next line from the bottom
"""
return self.next()
def readlines(self):
"""
Returns all remaining lines from the bottom of the file in reverse
"""
return [x for x in self]
頑張れ。これは、CSVファイルから行を逆にする簡単なプログラムです。
import csv
BC_file = open('Master.csv', 'rb')
BC_reader = csv.reader(BC_file)
next(BC_reader)
for row in reversed(list(BC_reader)):
print row[0]