我目前正在尝试在我的 linux 机器(Ubuntu 12.04.1 LTS)和我的新 Mac(OS X 10.7.4)之间移植一些代码,并且在使用 python 的 ctypes 模块访问 C 标准库时遇到了一些令人困惑的行为麦克。
为了说明这个问题,下面是一个最小的例子:
import ctypes as C
import numpy as np
libc = C.CDLL("/usr/lib/libc.dylib") #/usr/lib/libc.so.6 on ubuntu
np.arange(10,dtype="ubyte").tofile("test.bin") # create some test data
buffer_array = np.empty(10,dtype="ubyte") # create a reading buffer
buffer_array_c = np.ctypeslib.as_ctypes(buffer_array) # get the ctypes version of the buffer
c_file = libc.fopen("test.bin","r") # open the file through libc
libc.fread(buffer_array_c, 1, 10, c_file) # read from the file
libc.fclose(c_file)
print "Desired output:"
print np.fromfile("test.bin",dtype="ubyte")
print
print "Actual output:"
print buffer_array
在 Linux 上,这可以按预期工作,产生以下结果:
Desired output:
[0 1 2 3 4 5 6 7 8 9]
Actual output:
[0 1 2 3 4 5 6 7 8 9]
然而,在 Mac 上,我只是得到“分段错误:11”。
我已经对此进行了一些实验,将 fopen 调用替换为:
py_file = open("test.bin","r")
c_file = C.pythonapi.PyFile_AsFile(C.py_object(py_file))
这也适用于 Linux,但不适用于 Mac。
我认为问题来自使用 c_file 调用 fread,就好像我编写了一个最小的 C 函数来打开文件然后使用先前分配的缓冲区调用 fread,代码按预期执行。
我通常不是 Mac 用户,所以问题可能很明显,但任何帮助都会非常有用。
作为参考,我正在使用:
Python 2.7.3、Numpy 1.4.0 和 Ctypes 1.1.0
编辑:
为了给出一些背景信息,我正在尝试使用快速方法将非常大的二进制文件(~40-200 GB)逐个读入python。正如评论者在下面指出的那样,直接访问标准库 fread 和 fwrite 函数并没有真正提高性能。这是真的,但我不知道为什么。如果我要使用 numpy.fromfile 以块的形式读取一个大文件,我不会在每次读取时创建一个新的内存分配吗?
解决方案:
问题似乎源于文件句柄存储的 64 位/32 位差异。解决方案只是在使用之前显式设置每个 c 函数的 restype 和 argtypes。
即在 64 位机器上,我们把它放在 C.CDLL 调用之后:
lib.fopen.restype = C.c_long
lib.fread.argtypes = [C.c_void_p, C.c_size_t, C.c_size_t, C.c_long]
lib.fclose.argtypes = [C.c_long]
在 32 位机器上:
lib.fopen.restype = C.c_int
lib.fread.argtypes = [C.c_void_p, C.c_size_t, C.c_size_t, C.c_int]
lib.fclose.argtypes = [C.c_int]