【问题标题】:python read from fd directly into bytearraypython从fd直接读入bytearray
【发布时间】:2012-12-04 20:02:18
【问题描述】:

有没有办法从文件描述符(不是类似 IO 的对象)直接读取到bytearray

现在我使用一个临时的FileIO 对象进行调解,例如:

def fd_readinto(fd, ba):
    fio = io.FileIO(fd, closefd = False)
    return fio.readinto(ba)

【问题讨论】:

    标签: python io python-2.7


    【解决方案1】:

    没有这样做的功能,您的方法已经是最快的方法。

    我打算建议bytearray(mmap)array.fromfile,甚至是使用bytearraymemoryview 的自制软件os.read(),但FileIO.readinto尖叫得很快。 (这是有道理的,因为它只执行一个系统调用。)

    import os
    import mmap, io, array
    import timeit
    
    fn = 'path-to-largeish-file'
    
    def fd_readinto_mmap(fd, ba):
        m = mmap.mmap(fd, 0, access=mmap.ACCESS_READ)
        ba.extend(m)
        m.close()
    
    def fd_readinto_fio(fd, ba):
        sz = os.fstat(fd).st_size
        ba2 = bytearray(sz)
        with io.FileIO(fd, closefd = False) as fio:
            fio.readinto(ba2)
        ba.extend(ba2)
    
    def fd_readinto_array(fd, ba):
        ar = array.array('c')
        sz = os.fstat(fd).st_size
        fp = os.fdopen(fd, 'rb')
        ar.fromfile(fp, sz)
        ba.extend(ar)
    
    def fd_readinto_mv(fd, ba):
        stat = os.fstat(fd)
        blksize = getattr(stat, 'st_blksize', 4096)
        bufsize = stat.st_size
        buf = bytearray(bufsize)
        m = memoryview(buf)
        while True:
            b = os.read(fd, blksize)
            s = len(b)
            if not s: break
            m[:s], m = b, m[s:]
        writtenbytes = buffer(buf, 0, bufsize-len(m))
        ba.extend(writtenbytes)
    
    setup = """
    from __main__ import fn, fd_readinto_mmap, fd_readinto_fio, fd_readinto_array, fd_readinto_mv
    import os
    openfd = lambda : os.open(fn, os.O_RDONLY)
    closefd = lambda fd: os.close(fd)
    """
    
    
    reps = 2
    tests = {
        'fio' : "fd=openfd(); fd_readinto_fio(fd, bytearray()); closefd(fd)",
        'mmap': "fd=openfd(); fd_readinto_mmap(fd, bytearray()); closefd(fd)",
        'array': "fd=openfd(); fd_readinto_array(fd, bytearray());",
        'mv' : "fd=openfd(); fd_readinto_mv(fd, bytearray()); closefd(fd)",
    }
    
    width = max(map(len, tests))
    for n,t in tests.iteritems():
        time = timeit.timeit(t, setup, number=reps)
        print ("{:%s} {}" % width).format(n, time)
    

    在我的系统(OS X 10.14.6,Python 2.7.10)上,FileIO 是最快的选择:

    mmap  7.19839119911
    array 5.72453403473
    mv    0.49933886528
    fio   0.299485206604
    

    【讨论】:

    • 我不想这么说——但你的分析是有缺陷的。根据这些结果,fio 比其他任何东西都要快约 100,000 倍(这导致我的左眉毛抬得很高)。我花了一些时间检查你的代码,发现了这个缺陷。根据文档(docs.python.org/2.7/library/io.html#io.RawIOBase.readinto),“...readinto(b) 最多读取 len(b) 个字节...”在您的示例中,您传递的是一个空的 bytearray(),因此它返回零字节。如果你将 bytearray() 预增长到合适的大小,你会得到更理智的结果。
    • 你是对的!我更正了代码和基准。不过,这仍然是最快的方法。
    猜你喜欢
    • 2014-05-21
    • 2012-05-15
    • 1970-01-01
    • 1970-01-01
    • 2011-05-19
    • 2020-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多