在Python中我有一个文件流,我想将它的一部分复制到一个StringIO
.我想要尽可能快,最小的副本.
但如果我这样做:
data = file.read(SIZE)
stream = StringIO(data)
Run Code Online (Sandbox Code Playgroud)
我认为已完成2份,不是吗?从文件中复制一份数据,将另一份复制StringIO
到内部缓冲区中.我可以避免其中一个副本吗?我不需要临时的data
,所以我认为一份副本应该足够了
简而言之:使用StringIO无法避免2个副本.
一些假设:
file.read(SOME_BYTE_COUNT)
如果您的文件是二进制文件,请使用变体.答案很长:因为python字符串是不可变的而StringIO缓冲区不是,所以迟早要复制一个副本; 否则你会改变一个不可变的对象!对于您希望的可能,StringIO对象需要有一个专用方法,该方法直接从作为参数给出的文件对象中读取.没有这样的方法.
在 StringIO 之外,有一些解决方案可以避免额外的副本.在我的头顶,这将直接读取文件到可修改的字节数组,没有额外的副本:
import numpy as np
a = np.fromfile("filename.ext", dtype="uint8")
Run Code Online (Sandbox Code Playgroud)
使用它可能很麻烦,具体取决于您的用途,因为它是一个0到255之间的值数组,而不是一个字符数组.而且它的功能相当于一个StringIO对象,并使用np.fromstring
,np.tostring
,np.tofile
并在您想要切片符号应该得到你.你可能也需要np.insert
,np.delete
和np.append
.
我确信还有其他模块会做类似的事情.
TIMEIT:
这一切真的有多重要?好的,我们等着瞧.我已经制作了一个100MB的文件largefile.bin
.然后我使用两种方法读入文件并更改第一个字节.
$ python -m timeit -s "import numpy as np" "a = np.fromfile('largefile.bin', 'uint8'); a[0] = 1" 10 loops, best of 3: 132 msec per loop $ python -m timeit -s "from cStringIO import StringIO" "a = StringIO(); a.write(open('largefile.bin').read()); a.seek(0); a.write('1')" 10 loops, best of 3: 203 msec per loop
所以在我的情况下,使用StringIO比使用numpy慢50%.
最后,为了比较,直接编辑文件:
$ python -m timeit "a = open('largefile.bin', 'r+b'); a.seek(0); a.write('1')" 10000 loops, best of 3: 29.5 usec per loop
所以,它快了近4500倍.当然,它非常依赖于你要对文件做什么.改变第一个字节几乎没有代表性.但是使用这种方法,你可以在其他两个方面有一个良好的开端,并且由于大多数操作系统具有良好的磁盘缓冲,因此速度也可能非常好.
(如果您不允许编辑文件,因此希望避免制作工作副本的成本,有几种可能的方法来提高速度.如果您可以选择文件系统,Btrfs有一个副本 -写文件复制操作 - 使文件的副本几乎是即时的.使用任何文件系统的LVM快照可以实现相同的效果.)
不,没有额外的副本.用于存储数据的缓冲区是相同的.两者data
和可访问的内部属性StringIO.getvalue()
是相同数据的不同名称.
Python 2.7 (r27:82500, Jul 30 2010, 07:39:35)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-48)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import StringIO
>>> data = open("/dev/zero").read(1024)
>>> hex(id(data))
'0xea516f0'
>>> stream = StringIO.StringIO(data)
>>> hex(id(stream.getvalue()))
'0xea516f0'
Run Code Online (Sandbox Code Playgroud)
快速浏览一下来源显示,cStringIO
它既不会在构造上复制cStringIO.getvalue()
,也会在调用时复制,所以我不能重复上面的演示.
归档时间: |
|
查看次数: |
12293 次 |
最近记录: |