Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2012/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将整个二进制文件读入Python_Python_Numpy - Fatal编程技术网

将整个二进制文件读入Python

将整个二进制文件读入Python,python,numpy,Python,Numpy,我需要从Python导入一个二进制文件——内容是有符号的16位整数,big-endian 下面的堆栈溢出问题建议如何一次提取几个字节,但这是放大到读取整个文件的方式吗 我想创建一个函数,如: from numpy import * import os def readmyfile(filename, bytes=2, endian='>h'): totalBytes = os.path.getsize(filename) values = empty(totalB

我需要从Python导入一个二进制文件——内容是有符号的16位整数,big-endian

下面的堆栈溢出问题建议如何一次提取几个字节,但这是放大到读取整个文件的方式吗

我想创建一个函数,如:

from numpy import *
import os

def readmyfile(filename, bytes=2, endian='>h'):
    totalBytes = os.path.getsize(filename)
    values = empty(totalBytes/bytes)
    with open(filename, 'rb') as f:
        for i in range(len(values)):
            values[i] = struct.unpack(endian, f.read(bytes))[0]
    return values

filecontents = readmyfile('filename')

但这相当慢(文件是165924350字节)。有更好的方法吗?

一次读取和解压2个字节

values[i] = struct.unpack(endian,f.read(bytes))[0]

为什么不一次读取1024字节呢?

我会直接读取到EOF(这意味着检查是否接收到空字符串),这样就不需要使用range()和getsize了。
或者,使用
xrange
(而不是
range
)应该可以改善情况,特别是在内存使用方面。
此外,正如Falmari所说,同时读取更多数据将大大提高性能

也就是说,我不希望出现奇迹,因为我不确定列表是否是存储这么多数据的最有效方式。
使用NumPy的阵列和它的设施来实现这些功能怎么样?本节介绍如何使用numpyio.fread读取原始二进制文件。我相信这正是你需要的


注意:就个人而言,我从未使用过NumPy;然而,它的主要原因恰恰是处理大数据集——这就是你在问题中所做的。

使用
numpy.fromfile
我认为你在这里遇到的瓶颈是双重的

根据您的操作系统和光盘控制器,对
f.read(2)
的调用(如果
f
是一个大文件)通常会得到有效的缓冲--。换句话说,操作系统将从光盘中读取一个或两个扇区(光盘扇区通常为数KB)到内存中,因为这并不比从该文件中读取2个字节贵多少。额外的字节被高效地缓存在内存中,以便下次调用读取该文件。不要依赖这种行为——这可能是你的瓶颈——但我认为这里还有其他问题

我更关心的是将单字节转换为对numpy的简短调用和单次调用。它们根本不被缓存。您可以在Python的int列表中保留所有的简短内容,并在需要时(如果需要的话)将整个列表转换为numpy。您还可以从进行一次调用
struct.unpack\u,将缓冲区中的所有内容转换为一次一个简短的内容

考虑:

#!/usr/bin/python

import random
import os
import struct
import numpy
import ctypes

def read_wopper(filename,bytes=2,endian='>h'):
    buf_size=1024*2
    buf=ctypes.create_string_buffer(buf_size)
    new_buf=[]

    with open(filename,'rb') as f:
        while True:
            st=f.read(buf_size)
            l=len(st)
            if l==0: 
                break
            fmt=endian[0]+str(l/bytes)+endian[1]    
            new_buf+=(struct.unpack_from(fmt,st))

    na=numpy.array(new_buf)        
    return na

fn='bigintfile'

def createmyfile(filename):
    bytes=165924350
    endian='>h'
    f=open(filename,"wb")
    count=0

    try: 
        for int in range(0,bytes/2):
            # The first 32,767 values are [0,1,2..0x7FFF] 
            # to allow testing the read values with new_buf[value<0x7FFF]
            value=count if count<0x7FFF else random.randint(-32767,32767)
            count+=1
            f.write(struct.pack(endian,value&0x7FFF))

    except IOError:
        print "file error"

    finally:
        f.close()

if not os.path.exists(fn):
    print "creating file, don't count this..."
    createmyfile(fn)
else:    
    read_wopper(fn)
    print "Done!"
如果您不需要短裤是numpy,此函数将在6秒内运行。所有这些都是在OS X、python 2.6.1 64位、2.93 gHz核心i7、8 GB ram上实现的。如果将
read\u wopper
中的
buf\u size=1024*2
更改为
buf\u size=2**16
运行时间为:

real        0m10.810s
user        0m10.156s
sys         0m0.651s
所以,我认为,您的主要瓶颈是解包的单字节调用,而不是从光盘读取的2字节数据。您可能希望确保您的数据文件没有碎片化,并且如果您使用的是OS X,则您的(和)没有碎片化


编辑我发布了完整的代码来创建并读取一个int的二进制文件。在我的iMac上,读取随机整数文件的时间始终小于15秒。它需要大约1:23的时间来创造,因为创造是一次短一个

我也遇到了同样的问题,尽管在我的特殊情况下,我不得不转换一个非常奇怪的二进制格式(500MB)文件,其中包含166个元素的交错块,这些元素是3字节有符号整数;因此,我也遇到了从24位到32位有符号整数的转换问题,这会稍微降低速度

我已经使用NumPy的memmap(这只是使用Python的memmap的一种简便方法)和struct.unpack在文件的大部分上解决了这个问题

有了这个解决方案,我可以在大约90秒内转换(读、写、写)整个文件(用time.clock()计时)


我可以上传部分代码。

我认为速度很慢,因为
bytes=2
。读取150mb的文件会很慢。你期待什么?它有多慢?实际上只需要3.5分钟(根据unix
time
),但我可以使用
readBin
(我有数千个这样的文件…)在不到一分钟的时间内将其读入R。数据是清晰的二进制还是16位数字的ASCII表示?如果我这样做,它怎么知道它是一个16位整数而不是32位或其他什么?…它给了我一个错误:
TypeError:Struct()参数1必须是string,而不是int
我认为Struct.unpack不是最好的解决方案。这意味着要接受字符串,而不是二进制文件。我将研究NumPy,但加载后如何解析它?或者在循环中解析它?谢谢~在上面提供的链接中有一节介绍如何使用fread读取二进制文件。我将更新原始答案,以便更好地说明这一点。谢谢--该链接非常有用。它是否像
fromfile(filename,dtype='>i2')
一样简单?@Stephen,是的,这就是您需要做的所有事情。如果Karl在答案中提到了这一点,那么这是最好最简单的答案。根据我的经验,numpy.fromfile非常快速且易于使用。谢谢--明天将尝试此功能,尽管目前正在使用numpy.filefrom--但这对于未安装numpy的机器来说可能非常好(这对于我管理的所有不同的机器来说都不是微不足道的)!嗯…仍然是2M50(OS X,Python 2.6 64位,4GB内存)…感谢您对缓存的深入了解。'~@Stephen:您的光盘有什么不寻常的地方吗?光盘格式是NTFS还是完全的还是碎片化的?如果是NTFS,OS X NTFS驱动程序速度不快。我将发布完整的代码,并在相对空的HFS驱动器上试用……奇怪的是,它是OS X扩展的(日志记录)但是bash-3.2$time python test.py正在创建文件,不算这个……真正的2m28.376s用户2m6.882s sys 0m3.664s bash-3.2$time python test.py完成了!真正的0m28.485s用户0m23.273s sys 0m1.509soops,格式不好——无论如何,wri
real        0m10.810s
user        0m10.156s
sys         0m0.651s