如何恢复读取csv文件?

时间:2019-04-07 15:15:25

标签: python python-3.x csv

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,我如何才能像示例一样继续读取?

5 个答案:

答案 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的建议。