Python 读取大文件 chunk(block_size) 的疑惑

2023-08-03 15:27:40 +08:00
 evemoo

生成一个 10 行的文本文件,每一行以 "\n" 结尾,统计行数为 10 。

def generate_file():
    with open("line.log", "w") as f:
        for i in range(1, 10+1):
            f.write(f"Line is: your target line{i} to print\n")

def chunked_file_reader(fp, block_size=4 * 1024):
    while True:
        chunk = fp.read(block_size)
        if not chunk:
            break
        yield chunk

def get_line_count(fname):
    count = 0
    with open(fname) as fp:
        for chunk in chunked_file_reader(fp):
            count += chunk.count("\n")
    return count


generate_file()
line_count = get_line_count("line.log")
# > 10

block_size 亦或者说 buffering 传入的大小是每一行的长度,count 结果会变成 9 ,求解

def return_count(fname):
    count = 0
    with open(fname) as fp:
        line = fp.readline()
        for chunk in chunked_file_reader(fp, len(line)):
            count += chunk.count("\n")
    return count


generate_file()
line_count = get_line_count("line.log")
# > 9
1520 次点击
所在节点    Python
9 条回复
NoOneNoBody
2023-08-03 15:38:22 +08:00
最后一行没有\n 的,是 EOF
evemoo
2023-08-03 15:43:43 +08:00
@NoOneNoBody
如果我去掉 line = fp.readline() 这行直接传 36 (每一行的长度),返回值也是 10
如果加上这一行打印每一个 chunk ,则是从第二行开始了:Line is: your target line2 to print

所以我的疑惑是:open 里面的函数 read 、readline 、readlines 会影响后续的 chunk 读取?
yushenglin
2023-08-03 16:05:46 +08:00
你用 readline()操作得到时候,文件流已经操作到第一行后面了,你后面就只能读到 9 个,你可以试下用下 fp.seek(0),恢复到文件开始位置,又会变成 10 个了
NoOneNoBody
2023-08-03 16:07:59 +08:00
@evemoo #2
呃,我看漏了,前面说的不对

readline 是读取一行,完成时指针已经跳到第二行,所以统计少了一个\n
所以 line = fp.readline() 是没必要的,还造成后面的 for 读少了一行,包括行数和首行内容
如果有其他需求非要读取首行,那需要一个把指针复位到文件开始的操作,或者按这样写但最后合并处理(计数器要补加 1 )
evemoo
2023-08-03 16:17:33 +08:00
@yushenglin 确实是这样

如果要分页读取数据,比如 10 行总计 400 bytes ,假设分 5 页,每页两行、每页 80 bytes 。

fp.seek() 该怎么读取指定页面指定行呢?比如我想读取第三页的第二行
yushenglin
2023-08-03 16:56:35 +08:00
@evemoo 这种只能通过计算去处理了,暂时没想到什么好办法,可以期待一下其他大牛的回复
westoy
2023-08-03 17:04:39 +08:00
文本数据要效率的话, 最少要维护一个 offset_t[]的索引文件的

直接用 sqlite 吧, 别折腾了
marcolin18
2023-08-03 17:47:34 +08:00
@westoy 同意 sqlite ,或者 OP 说说场景
evemoo
2023-08-03 18:12:10 +08:00
@marcolin18 没有什么场景,就是最近遇到大文件读写指定行的时候发散思维到分页处理上。
后续会试试 sqlite 的,先谢谢上面各位了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/962105

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX