Как возобновить чтение 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?

Вам придется сохранить свой прогресс в другом файле.

Vulpex 07.04.2019 17:18

Что означает записать содержимое в другой файл, а затем начать сравнивать оба файла?

kino.jom 07.04.2019 17:20

Возможный дубликат CSV читать определенную строку

Omi 07.04.2019 17:20

Проще всего было бы сохранить количество строк, которые вы уже прочитали, и пропустить это количество вперед при следующем запуске.

Vulpex 07.04.2019 17:20

@mrHOT не дубликат. Сначала прочитайте вопрос, пожалуйста.

Vulpex 07.04.2019 17:21

Я просто хочу спросить, что вы имеете в виду под перезапуском, это выйти из программы, нажав crtl-c ??

Mobrine Hayde 07.04.2019 17:25

если вы прервете цикл после, скажем, 2 итераций, вы увидите, что цикл снова возобновляет чтение, поскольку итератор не сбрасывается. Можете ли вы объяснить больше, чего вы хотите достичь?

Jean-François Fabre 07.04.2019 17:31

@Jean-FrançoisFabre У меня проблема, когда программе внезапно не хватает памяти из-за другой непредсказуемой ситуации, из-за которой программа завершается. В этой ситуации мне нужно перезапустить программу, но я хочу, чтобы она возобновила последнюю строку записи.

kino.jom 07.04.2019 17:37

@ kino.jom, если это проблема, вы можете просто установить флаг, когда вы достигнете n времени чтения строк (например, 500 строк), вы можете, например, дать вашей программе отдохнуть в течение 4 секунд, вполне естественно, что ваш заканчивается память, если это большой цикл без тайм-аута (время сна или отдыха)

Mobrine Hayde 07.04.2019 17:45

@MobrineHayde Спасибо... поищу.

kino.jom 07.04.2019 17:47

Как сценарий узнает, должен ли он возобновить чтение или начать сначала?

martineau 07.04.2019 18:31

@MobrineHayde: приостановка программы не повлияет на объем используемой ею памяти — только ее завершение займет больше времени.

martineau 07.04.2019 19:27
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
12
646
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Для этого вам нужно отслеживать, насколько далеко вы прочитали файл на данный момент, 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

Вы можете добиться того же в своем коде, отслеживая, сколько строк вы прочитали в последний раз, и итерируя публикацию этого количества строк.

readline() может выполнять упреждающее чтение и буферизацию за кулисами, в результате чего file.tell() дает результаты, которые не обязательно совпадают с вашим прогрессом чтения.
PaulMcG 07.04.2019 21:55

В этом случае вы должны явно сохранять текущее местоположение каждый раз, что может быть немного затратным в вычислительном отношении, но это работает, и вот код:

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)
pathlib.Path.write_text упрощает многое из этого open/write/close материала. И пусть ваш обработчик исключений в get_last вызове update_last(0) - СУХОЙ!
PaulMcG 07.04.2019 21:53

@PaulMcG: метод Path.write_text() не был добавлен до Python 3.5, поэтому нет, использующий его, делает этот код совместимым с большим количеством версий ... кроме того, что делать это «старомодным» способом не так уж много работы в этом конкретном случае случае (ИМО). (На самом деле, я немного удивлен, что они вообще удосужились добавить такое тривиальное, как write_text().)

martineau 08.04.2019 20:04

mrHOT: FWIW, я думаю, что в целом это правильный подход, и ваша реализация, безусловно, очень лаконична. Тем не менее, открытие и закрытие файла last.txt каждый раз, когда читается строка, добавит много накладных расходов, особенно потому, что для этого требуется несколько вызовов ОС (что, как правило, очень дорого). У меня есть одно предложение: не записывать в него имя файла last.txt, потому что это предотвращает использование кода более чем с одним CSV-файлом одновременно. Кроме того, необходим дополнительный код для удаления файла, когда он больше не нужен...

martineau 08.04.2019 20:31

Используйте магию генераторов:

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)

Генератор приостановится, пока вы запускаете свою сложную бизнес-логику, а затем прозрачно возобновить, когда вы будете готовы к следующей строке.

Ответ принят как подходящий

Для этого вам нужно будет постоянно сохранять текущее местоположение в другом файле каждый раз, когда строка считывается из CSV-файла, что, конечно, добавит некоторые накладные расходы на ее обработку.

Я думаю, что создание Тип диспетчера контекста в сочетании с оператором 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

Другие вопросы по теме