import csv
with open('test.csv', 'r') as f:
reader = csv.reader(f)
for i in reader:
print(i)
CSV
id,name
001,jane
002,winky
003,beli
...
到目前为止,该程序只能读取一次csv。如果再次重新启动,程序将从第一行001
中读取。如果程序在002
处停止读取,那么下一个开始读取的将是003
,我如何才能像示例一样继续读取?
答案 0 :(得分:1)
为此,每次从CSV文件中读取一行时,您都需要将当前位置连续保存在另一个文件中,这当然会增加一些处理开销。
我认为与Context Manager Type语句一起创建with
是解决该问题的一种非常好的方法,并将在一定程度上将开销最小化。
下面的代码实现了用于读取CSV文件的内容管理器,并允许在读取整个文件之前(在with
语句的上下文中被中断的情况下,自动恢复读取它们。
这是通过创建一个单独的“状态”文件来完成的,以跟踪成功读取的最后一行。如果在读取过程中没有异常发生,则此文件将被删除,但是,不会发生,并且如果存在则将保留。因此,下次读取文件时,将检测到现有的状态文件,并将其用于允许从先前中断的地方开始读取。
值得注意的是,由于每个可恢复的CSV阅读器都是一个单独的对象,因此您一次可以创建和使用多个对象。在读取CSV文件时,每个文件的关联“状态”文件保持打开状态,因此不必在每次更新其内容时重复打开和关闭。
import csv
import os
class ResumableCSVReader:
def __init__(self, filename):
self.filename = filename
self.state_filename = filename + '.state'
self.csvfile = None
self.statefile = None
def __enter__(self):
self.csvfile = open(self.filename, 'r', newline='')
try: # Open and read state file
with open(self.state_filename, 'r', buffering=1) as statefile:
self.start_row = int(statefile.read())
except FileNotFoundError: # No existing state file.
self.start_row = 0
self.statefile = open(self.state_filename, 'w', buffering=1)
return _CSVReaderContext(self)
def __exit__(self, exc_type, exc_val, exc_tb):
if self.csvfile:
self.csvfile.close()
if self.statefile:
self.statefile.close()
if not exc_type: # No exception?
os.remove(self.state_filename) # Delete state file.
class _CSVReaderContext:
def __init__(self, resumable):
self.resumable = resumable
self.reader = csv.reader(self.resumable.csvfile)
# Skip to start row.
for _ in range(self.resumable.start_row):
next(self.reader)
self.current_row = self.resumable.start_row
def __iter__(self):
return self
def __next__(self):
self.current_row += 1
row = next(self.reader)
# Update state file.
self.resumable.statefile.seek(0)
self.resumable.statefile.write(str(self.current_row)+'\n')
return row
if __name__ == '__main__':
csv_filename = 'resumable_data.csv'
# Read a few rows and raise an exception.
try:
with ResumableCSVReader(csv_filename) as resumable:
for _ in range(2):
print('row:', next(resumable))
raise MemoryError('Forced') # Cause exception.
except MemoryError:
pass # Expected, suppress to allow test to keep running.
# CSV file is now closed.
# Resume reading where left-off and continue to end of file.
print('\nResume reading\n')
with ResumableCSVReader(csv_filename) as resumable:
for row in resumable:
print('row:', row)
print('\ndone')
输出:
row: ['id', 'name']
row: ['001', 'jane']
Resume reading
row: ['002', 'winky']
row: ['003', 'beli']
done
答案 1 :(得分:0)
为此,您需要跟踪到目前为止已读取文件的距离,file.tell()
可能会派上用场。之后,您可以使用file.seek()
从此处开始读取文件。
代码看起来像:
def read_from_position(last_position):
file = open("file_location")
file.seek(last_position)
file.readline() # Do what you want with this
return file.tell() # this is the updated last position
通过跟踪上次读取的行数并迭代发布那么多的行数,可以在代码中实现相同的目的。
答案 2 :(得分:0)
在这种情况下,您每次必须显式保存当前位置,这可能会在计算上花费一些时间,但是它可以工作,并且代码如下:
import csv
def update_last(x):
with open('last.txt', 'w') as file:
file.write(str(x))
def get_last():
try:
with open('last.txt', 'r') as file:
return int(file.read().strip())
except:
with open('last.txt', 'w') as file:
file.write('0')
return 0
with open('your_file.txt', 'r') as f:
reader = csv.reader(f)
last = get_last() + 1
current = 1
for i in reader:
if current < last:
current += 1
continue
print(i)
current += 1
update_last(current)
答案 3 :(得分:0)
使用生成器的魔力:
def get_rows(infile='test.csv'):
with open(infile) as f:
reader = csv.reader(f)
for row in reader:
yield row
for id, name in get_rows():
out = some_complex_business_logic(id, name)
print(out)
运行复杂的业务逻辑时,生成器将暂停, 然后在准备下一行时透明地恢复。
答案 4 :(得分:-1)
如果要在运行时恢复,将进度保存为行变量可能是一种解决方案。例如。
import csv
def read_from_position(position):
with open('test.csv', 'r') as f:
reader = csv.reader(f)
cur_pos = 0
for i in reader:
if cur_pos >= position:
# do stuff
cur_pos += 1
如果您想继续阅读,请在重新启动程序之后,遵循@Vulpex的建议。