現在、Linuxマシン(Ubuntu 12.04.1 LTS)と新しいMac(OS X 10.7.4)の間でコードを移植しようとしていますが、Pythonのctypesモジュールを使用してC標準ライブラリにアクセスすると混乱する動作が発生します。 Mac。
問題を説明するために、以下は最小限の例です。
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に1つずつ読み込む高速メソッドを試しています。コメント提供者が以下で指摘しているように、標準ライブラリの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]