【问题标题】:python read bigger csv line by linepython逐行读取更大的csv
【发布时间】:2018-12-08 08:56:39
【问题描述】:

您好,我有巨大的 csv 文件 (1GB) 可以更新(服务器经常添加新值)

我想在 python 中逐行读取这个文件(不加载内存中的所有文件),我想“实时”读取这个

这是我的 csv 文件的示例:

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

第一次我想在我的示例中获取文件的标题(列名)我想得到这个:id,name,lastname

第二次,我想逐行读取这个文件,而不是将所有文件加载到内存中

第三次我想尝试在 10 秒之间读取新值(例如 sleep(10))

我使用 pandas 搜索实际解决方案 我读了这个话题: Reading a huge .csv file

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

但我不明白, 1)我不知道我的 csv 文件的大小,如何定义 chunksize ? 2)当我读完时,如何告诉熊猫尝试在 10 秒之间读取新值(例如)?

感谢您的帮助

【问题讨论】:

  • 你的问题我不清楚。你能定义read new value between 10 seconds吗?
  • 我有一个将数据添加到这个 csv 文件的服务器当服务器将此数据添加到 csv 文件时,我希望我的 python 程序能够检测到它并显示给我我认为唯一的解决方案就是做一个无限循环,在这个循环中,我建议每10秒看一次,如果有新数据10秒只是一个例子,可以是1秒,1分钟...

标签: python pandas csv


【解决方案1】:

块大小是它一次读取的行数,因此它不依赖于文件大小。在文件末尾,for 循环将结束。 块大小取决于进程的最佳数据大小。在某些情况下,1GB 不是问题,因为它可以放入内存中,并且您不需要块。如果您不同意一次加载 1GB,您可以选择例如 1M 行 chunksize = 1e6,因此行长度约为 20 个字母,这将小于 100M,这似乎相当低,但您可以更改参数视你的情况而定。

当您需要读取更新的文件时,您只需再次启动 for 循环。

如果您不想阅读整个文件只是为了了解它没有更改,您可以查看它的修改时间 (details here)。如果没有变化,请跳过阅读。

如果问题是关于 10 秒后阅读,则可以在无限循环中进行睡眠,例如:

import time

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

事实上,这个周期会超过 10 秒,因为 do_what_you_need() 也需要时间。

【讨论】:

  • 好的,但我的问题是,一旦循环完成,我们如何使用 chunksize 实时读取,我必须重新读取整个文件才能获取最后的数据?
  • 是的,chunksize 不是为了那个。
【解决方案2】:

首先,1GB 并不是巨大 - 几乎任何现代设备都可以将其保存在工作内存中。其次,pandas 不允许您浏览 CSV 文件,您只能告诉它要“加载”多少数据 - 如果您想做更高级的 CSV 处理,我建议使用内置的 csv 模块。

不幸的是,csv 模块的reader() 将为您的文件生成一个可耗尽的迭代器,因此您不能将其构建为一个简单的循环并等待下一行可用 - 您必须收集新行手动然后将它们喂给它以达到您想要的效果,例如:

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 

【讨论】:

  • 但是 reader if loop for row in reader: 包含我的 csv 文件的所有数据,这不是我想要的。我想一次将 1 行加载到内存中
  • @ilapasle - 不,它没有。实际上,上面的 逐行加载数据,而不是将整个文件保存在内存中(与 pandas 不同),除了第二部分,f.readlines() 部分(它只在内存中存储更新到文件)。如果即使对于 CSV 文件更新,逐行更新也很重要,请检查上面的更新。
【解决方案3】:

如果问题是关于读取文件尾部的,我不知道在 pandas 中执行此操作的好方法,但您可以做一些变通方法。

第一个想法只是在没有熊猫的情况下读取文件并记住最后一个位置。下次需要阅读时,可以使用seek。或者您可以尝试使用 StringIO 作为 pandas.read_csv 的源来实现从 pandas 中查找和读取

另一个解决方法是使用 Unix 命令tail 剪切最后 n 行,如果你确定那里一次添加的不是太多的话。它会读取整个文件,但比使用 pandas 读取和解析所有行要快得多。在非常长的文件上仍然寻找速度更快。这里你需要检查是否添加了太多行(你没有看到最后处理的id),这种情况下你需要获取更长的tail或者读取整个文件。

所有这些都涉及额外的代码、逻辑和错误。其中之一是最后一行可能被破坏(如果你在写它的那一刻阅读)。所以我最喜欢的方式就是从txt文件切换到sqlite,这是一个SQL兼容的数据库,将数据存储在文件中,不需要特殊的过程来访问它。它具有python library,使其易于使用。它将处理所有长文件的员工,同时读写,只读取您需要的数据。只需保存最后处理的 id 并发出这样的请求SELECT * FROM table_name WHERE id > last_proceesed_id;。好吧,只有当您还控制服务器代码并且可以以这种格式保存时,这才有可能。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-26
    • 1970-01-01
    • 1970-01-01
    • 2013-10-11
    • 2017-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多