V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
evemoo
V2EX  ›  Python

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

  •  
  •   evemoo · 267 天前 · 1283 次点击
    这是一个创建于 267 天前的主题,其中的信息可能已经有所发展或是发生改变。

    生成一个 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
    
    9 条回复    2023-08-03 18:12:10 +08:00
    NoOneNoBody
        1
    NoOneNoBody  
       267 天前
    最后一行没有\n 的,是 EOF
    evemoo
        2
    evemoo  
    OP
       267 天前
    @NoOneNoBody
    如果我去掉 line = fp.readline() 这行直接传 36 (每一行的长度),返回值也是 10
    如果加上这一行打印每一个 chunk ,则是从第二行开始了:Line is: your target line2 to print

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

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

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

    fp.seek() 该怎么读取指定页面指定行呢?比如我想读取第三页的第二行
    yushenglin
        6
    yushenglin  
       267 天前
    @evemoo 这种只能通过计算去处理了,暂时没想到什么好办法,可以期待一下其他大牛的回复
    westoy
        7
    westoy  
       267 天前   ❤️ 1
    文本数据要效率的话, 最少要维护一个 offset_t[]的索引文件的

    直接用 sqlite 吧, 别折腾了
    marcolin18
        8
    marcolin18  
       267 天前
    @westoy 同意 sqlite ,或者 OP 说说场景
    evemoo
        9
    evemoo  
    OP
       267 天前
    @marcolin18 没有什么场景,就是最近遇到大文件读写指定行的时候发散思维到分页处理上。
    后续会试试 sqlite 的,先谢谢上面各位了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2843 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 06:53 · PVG 14:53 · LAX 23:53 · JFK 02:53
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.