Python читать больше CSV построчно - PullRequest
0 голосов
/ 29 июня 2018

Здравствуйте, у меня есть огромный CSV-файл (1 ГБ), который можно обновить (сервер часто добавляет новое значение)

Я хочу в python читать этот файл построчно (не загружать весь файл в память), и я хочу читать это в «реальном времени»

это пример моего CSV-файла:

id,name,lastname
1,toto,bob
2,tutu,jordan
3,titi,henri

в первый раз, когда я хочу получить заголовок файла (имя столбца) в моем примере, я хочу получить это: id, имя, фамилия

и во второй раз я хочу прочитать этот файл построчно, а не загрузить весь файл в память

и в третий раз я хочу попробовать прочитать новое значение за 10 секунд (например, с помощью sleep (10))

я ищу актуальное решение с использованием панд я читаю эту тему: Чтение огромного CSV-файла

import pandas as pd
chunksize = 10 ** 8
for chunk in pd.read_csv(filename, chunksize=chunksize):
    process(chunk)

но я не понимаю, 1) я не знаю размер моего CSV-файла, как определить размер фрагмента? 2) когда я закончу читать, как панды будут пытаться прочитать новое значение между 10 секундами (например)?

спасибо за аванс за помощь

Ответы [ 3 ]

0 голосов
/ 29 июня 2018

Прежде всего, 1 ГБ не является огромным - практически любое современное устройство может сохранить это в своей рабочей памяти. Во-вторых, pandas не позволяет вам ковыряться в CSV-файле, вы можете только указать, сколько данных «загрузить» - я бы предложил использовать встроенный модуль csv, если вы хотите выполнить более сложную обработку CSV.

К сожалению, reader() модуля csv создаст исчерпывающий итератор для вашего файла, поэтому вы не можете просто построить его как простой цикл и ждать следующих строк стать доступным - вам придется собирать новые строки вручную, а затем подавать их для достижения желаемого эффекта, например:

import csv
import time

filename = "path/to/your/file.csv"

with open(filename, "rb") as f:  # on Python 3.x use: open(filename, "r", newline="")
    reader = csv.reader(f)  # create a CSV reader
    header = next(reader)  # grab the first line and keep it as a header reference
    print("CSV header: {}".format(header))
    for row in reader:  # iterate over the available rows
        print("Processing row: {}".format(row))  # process each row however you want
    # file exhausted, entering a 'waiting for new data' state where we manually read new lines
    while True:  # process ad infinitum...
        reader = csv.reader(f.readlines())  # create a CSV reader for the new lines
        for row in reader:  # iterate over the new rows, if any
            print("Processing new row: {}".format(row))  # process each row however you want
        time.sleep(10)  # wait 10 seconds before attempting again

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

ОБНОВЛЕНИЕ : Вышеперечисленное обрабатывает файл CSV построчно, он никогда не загружается целиком в рабочую память. Единственная часть, которая на самом деле загружает более одной строки в памяти, - это когда происходит обновление файла, когда он собирает все новые строки, потому что быстрее обрабатывать их таким образом и, если вы не ожидаете миллионов строк обновлений между двумя проверки, влияние на память будет незначительным. Однако, если вы хотите, чтобы эта часть также обрабатывалась построчно, вот как это сделать:

import csv
import time

filename = "path/to/your/file.csv"

with open(filename, "rb") as f:  # on Python 3.x use: open(filename, "r", newline="")
    reader = csv.reader(f)  # create a CSV reader
    header = next(reader)  # grab the first line and keep it as a header reference
    print("CSV header: {}".format(header))
    for row in reader:  # iterate over the available rows
        print("Processing row: {}".format(row))  # process each row however you want
    # file exhausted, entering a 'waiting for new data' state where we manually read new lines
    while True:  # process ad infinitum...
        line = f.readline()  # collect the next line, if any available
        if line.strip():  # new line found, we'll ignore empty lines too
            row = next(csv.reader([line]))  # load a line into a reader, parse it immediately
            print("Processing new row: {}".format(row))  # process the row however you want
            continue  # avoid waiting before grabbing the next line
        time.sleep(10)  # wait 10 seconds before attempting again 
0 голосов
/ 29 июня 2018

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

Первая идея - просто прочитать файл без панд и запомнить последнюю позицию. В следующий раз, когда вам нужно будет прочитать, вы можете использовать seek . Или вы можете попытаться реализовать поиск и чтение из панд, используя StringIO в качестве источника для pandas.read_csv

Другой обходной путь - использовать команду Unix tail, чтобы вырезать последние n строк, если вы уверены, что там, где добавлено не слишком много сразу. Он прочитает весь файл, но это намного быстрее, чем чтение и разбор всех строк с помощью панд. Тем не менее, поиск очень быстр на очень длинных файлах. Здесь вам нужно проверить, не добавлено ли слишком много строк (вы не видите последний обработанный идентификатор), в этом случае вам нужно получить более длинный хвост или прочитать весь файл.

Все, что связано с дополнительным кодом, логикой, ошибками. Одна из них заключается в том, что последняя строка может быть разбита (если вы читаете в тот момент, когда она пишется). Поэтому мне больше всего нравится просто переключаться с txt-файла на sqlite, который является SQL-совместимой базой данных, которая хранит данные в файле и не требует специального процесса для доступа к ним. Он имеет библиотеку Python , которая делает его простым в использовании. Он будет обрабатывать весь персонал с длинными файлами, одновременным написанием и чтением, читая только те данные, которые вам нужны. Просто сохраните последний обработанный идентификатор и сделайте запрос вот так SELECT * FROM table_name WHERE id > last_proceesed_id;. Это возможно только в том случае, если вы также управляете кодом сервера и можете сохранять в этом формате.

0 голосов
/ 29 июня 2018

Размер блока - это количество строк, которые он будет читать одновременно, поэтому он не зависит от размера файла. В конце файла цикл for закончится. Размер чанка зависит от оптимального размера данных для процесса. В некоторых случаях 1 ГБ не является проблемой, так как он может поместиться в памяти, и вам не нужны чанки. Если у вас не все в порядке с загрузкой 1 ГБ сразу, вы можете выбрать, например, 1 М строк chunksize = 1e6, поэтому при длине строки около 20 букв это будет меньше, чем 100 МБ, что кажется достаточно низким, но вы можете изменить параметр в зависимости от ваших условий.

Когда вам нужно прочитать обновленный файл, вы просто запускаете цикл for еще раз.

Если вы не хотите читать весь файл, просто чтобы понять, что он не изменился, вы можете посмотреть на время его модификации ( подробности здесь ). И пропустите чтение, если оно не изменилось.

Если вопрос о чтении через 10 секунд, это можно сделать в бесконечном цикле со сном, например:

import time

while True:
    do_what_you_need()
    time.sleep(10)

Фактически, период будет больше 10 секунд, так как do_what_you_need () также требует времени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...