python 读取二进制文件的速度 - V2EX
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
raiz
V2EX    Python

python 读取二进制文件的速度

  •  
  •   raiz 2015-10-14 15:23:47 +08:00 6472 次点击
    这是一个创建于 3707 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我需要从 .wav 读取 pcm 数据,一开始使用 open() 直接打开文件,然后 read() 每次读一个样本,
    测试一个 5.49M 文件, 时长 29s, 的文件,读到结尾,花了 1850 ms, 如果要处理数据。
    能否通过先全部读到内存来加速, BytesIO 似乎只做这个事的, 但是我不知道它把文件读到内存是一次性的还是怎样,需要多少时间,测试花的时间差不多

    from io import BytesIO import time if __name__ == '__main__': with open('1875.wav', 'rb') as raw_file: ①# file = raw_file # 这句是直接从文件读取的方式 ②file = BytesIO(raw_file.read()) # 这句是用了 BytesIO start_time = time.time() buff = [] while True: byte = file.read(1) if byte: buff.append(byte) else: break end_time = time.time() print(' time using: ', (end_time - start_time) * 1000, 'msec') 

    使用①的情况下 time using: 1862.1060848236084 msec
    使用①的情况下 time using: 1743.0999279022217 msec
    时间时有浮动的
    所以我想知道, ByteIO 是怎样工作的, 它能达到我的目的吗?

    14 条回复    2015-10-15 13:57:15 +08:00
    raiz
        1
    raiz  
    OP
       2015-10-14 15:34:57 +08:00
    @raiz
    使用①的情况下 time using: 1862.1060848236084 msec
    使用②的情况下 time using: 1743.0999279022217 msec
    waklin
        2
    waklin  
       2015-10-14 16:35:01 +08:00
    你用的二进制方式打开的文件,直接调用 raw_file.read()就已经将文件读入到内存中了。

    # -*- coding: utf-8 -*-

    import time
    if __name__ == '__main__':
    with open('TenMiLines-small.csv', 'rb') as raw_file:
    start_time = time.time()
    buff = raw_file.read()
    for b in buff:
    # print repr(b)
    # b 就是你所说的一个样本
    pass
    end_time = time.time()
    print(' time using: ', (end_time - start_time) * 1000, 'msec')
    waklin
        3
    waklin  
       2015-10-14 16:37:33 +08:00
    把 open 的文件换成 1875.wav
    raiz
        4
    raiz  
    OP
       2015-10-14 17:11:57 +08:00
    @waklin hey 谢谢, 我知道 raw_file.read() 是读到内存,但是注意我的 start_time = time.time() 是放在它之后的,我是想测试从 BytesIo 读取的速度与 从 raw_file 的比较。
    waklin
        5
    waklin  
       2015-10-14 17:46:40 +08:00
    1. 你的第一个帖子里提到你处理 5.49M 的文件总共花了 29m ,读到结尾,花了 1850 ms ,如果我理解的没有错,现在你想提高的是 1850ms 的时间
    2. 一个 10M 的文件我用我给出的代码的 file.read()到 buff 里,然后遍历 buff 仅花了 50ms 左右,不知道你的 1850ms 是怎么回事
    3. BytesIO 和 raw_file 区别
    BytesIO 维护的一段内存中的数据, read 的话,仅操作内存
    raw_file 相当于一个文件游标, read 的话,是从硬盘上读取
    理论上访问硬盘的速度会低于访问内存的速度,但是由于现在硬盘都会有单独的缓存,读取的数据不是很大时,差别不明显。
    xylophone21
        6
    xylophone21  
       2015-10-14 19:16:28 +08:00
    仅看代码,第一怀疑 buff.append(byte)这句,没验证。
    xylophone21
        7
    xylophone21  
       2015-10-14 19:16:56 +08:00
    看错了,请忽略我上面的帖子。。
    mengzhuo
        8
    mengzhuo  
       2015-10-14 22:15:49 +08:00 via iPhone
    mark 目测需要流式处理
    WKPlus
        9
    WKPlus  
       2015-10-14 23:34:53 +08:00
    我的理解 BytesIO 的用法和 StringIO 类似,是用来提供类似文件操作一样的接口来操作内存中的 bytes 和 string 的,而不是用来全部读到内存来加速的。

    你原来的程序比较慢,估计是 file.read(1)引起的,每次只读一个字节干那要循环多少次?
    ryd994
        10
    ryd994  
       2015-10-15 05:47:45 +08:00
    差别不会太大的,操作系统有缓存
    可以考虑 os.posix_fadvise ,可能会更好, POSIX_FADV_SEQUENTIAL
    ryanking8215
        11
    ryanking8215  
       2015-10-15 09:00:16 +08:00
    class io.BytesIO([initial_bytes])
    A stream implementation using an in-memory bytes buffer.

    raw_file 是文件流,如果 open 时如果是 rb 的, buffering=-1 的,则使用内置的 chunked buffer ,这是针对你参数的结果。

    从 file.read(1)上看,都是从 file 流里取 1 个字节。从效率上看, BytesIO 是内存访问, raw_file 是 buffer+Filesystem io 的结果,所以貌似慢一点。

    但这都不是正确的打开方式,要效率高就要 chunk 读,减少 FS IO 和循环次数。 BytesIO 更大的意义在抽象层次上, fs 和 buffer 都能通过 file io 访问,是不是 test 的时候简单一点?

    如果错误请指正,欢迎探讨。 -)
    raiz
        12
    raiz  
    OP
       2015-10-15 09:35:45 +08:00
    @ryanking8215 你说的几个点应该是导致两者时间接近的原因, 默认的 fs 是有 buffer 的,而我每次只读一个 字节 ,所以那个 buffer 是够用的,所以下限不再是文件系统 io 的速度,而是在内存总遍历所有字节的速度。 说到正确的打开方式, 比如说 photoshop , 打开图片,或 audition 打开一个音频文件,应该是整一个读到内存中的吧,策略是怎样的呢?
    ryanking8215
        13
    ryanking8215  
       2015-10-15 10:16:31 +08:00
    @raiz 这要看具体应用啊,比如图片,要显示总是需要全部的数据。比如音频视频,文件很大,播放是流的方式,只需要分片取,不需要全部数据都进 memory
    matthewgao
        14
    matthewgao  
       2015-10-15 13:57:15 +08:00
    我和 @ryanking8215 的意见一样。

    我觉得也没有必要这么做,在你的程序里通过文件流还是 ByteIO 基本上等于没有区别

    如果文件很大不可能都读到内存中来,如果你内存只有 2G ,那么 4G 的电影肿么打开, swap 到死啊。。

    还是根据需求吧,如果你真的文件很小,那么你索性就一次性都读进来,循环都不用
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5498 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 01:42 PVG 09:42 LAX 17:42 JFK 20:42
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86