Python ctypes:Python文件对象<-&燃气轮机;C文件*
我正在使用ctypes用Python包装一个C库(我可以控制它)。我想用声明包装一个C函数:Python ctypes:Python文件对象<-&燃气轮机;C文件*,python,ctypes,Python,Ctypes,我正在使用ctypes用Python包装一个C库(我可以控制它)。我想用声明包装一个C函数: int fread_int( FILE * stream ); 现在;我想用python打开文件,然后使用python文件对象(以某种方式??)访问底层文件*对象并将其传递给C函数: # Python fileH = open( file , "r") value = ctypes_function_fread_int( ????? ) fileH.close() Python文件*映射可能吗 Jo
int fread_int( FILE * stream );
现在;我想用python打开文件,然后使用python文件对象(以某种方式??)访问底层文件*对象并将其传递给C函数:
# Python
fileH = open( file , "r")
value = ctypes_function_fread_int( ????? )
fileH.close()
Python文件*映射可能吗
JoakimPython文件对象不一定具有底层C级
文件*
——至少,除非您愿意将代码绑定到非常特定的Python版本和平台
我建议改为使用Python文件对象的fileno
获取文件描述符,然后使用ctypes
调用C运行时库的fdopen
来生成一个文件*
。这是一种非常可移植的方法(您也可以采用另一种方法)。最大的问题是,在同一个文件描述符上打开的两个对象(Python文件对象和C文件*
)的缓冲将是分开的,因此请确保根据需要经常刷新所述对象(或者,如果更方便且与您的预期用途兼容,则以无缓冲方式打开这两个对象)。
我尝试了基于fileno
的解决方案,但对打开两次文件感到非常不舒服;我也不清楚如何避免fdopen()
的返回值泄漏
最后我写了一个微观的C扩展:
static PyObject cfile(PyObject * self, PyObject * args) {
PyObject * pyfile;
if (PyArg_ParseTuple( 'O' , &pyfile)) {
FILE * cfile = PyFile_AsFile( pyfile );
return Py_BuildValue( "l" , cfile );
else
return Py_BuildValue( "" );
}
它使用PyFile\u AsFile
并随后将FILE*
指针作为纯指针值返回给Python,Python会将该值传递回需要FILE*
输入的C函数。至少它起作用了
Joakim我也遇到了同样的问题 请查看此文件:
您可以从中使用PyFile\u AsFile。如果您想使用
stdout
/stdin
/stderr
,您可以从标准C库导入这些变量
libc = ctypes.cdll.LoadLibrary('libc.so.6')
cstdout = ctypes.c_void_p.in_dll(libc, 'stdout')
或者,如果出于某种原因希望避免使用void*
:
class FILE(ctypes.Structure):
pass
FILE_p = ctypes.POINTER(FILE)
libc = ctypes.cdll.LoadLibrary('libc.so.6')
cstdout = FILE_p.in_dll(libc, 'stdout')
改编自
我试过这个:
#if PY_MAJOR_VERSION >= 3
if (PyObject_HasAttrString(pyfile, "fileno")) {
int fd = (int)PyLong_AsLong(PyObject_CallMethod(pyfile, "fileno", NULL));
if (PyObject_HasAttrString(pyfile, "mode")) {
char *mode = PyUnicode_AsUTF8AndSize(
PyObject_CallMethod(pyfile, "mode", NULL), NULL);
fp = fdopen(fd, mode);
}
else {
return PyErr_Format(PyExc_ValueError,
"File doesn’t have mode attribute!");
}
}
else {
return PyErr_Format(PyExc_ValueError,
"File doesn’t have fileno method!");
}
#else
fp = PyFile_AsFile(pyfile);
#endif
看起来它可能会工作。非常感谢-我有一种感觉,C级文件*不会非常健壮。我不知道python文件对象的fileno属性,但这似乎是一种自然的方式。我从SO导入stdin/stdout/stderr时遇到了问题,因此不可能构建正式的结构。你的建议救了我。谢谢。谢谢-这是一个比我更好的解决方案。不幸的是PyFile\u AsFile在Python 3 C API中不存在。@MikhailKorobov:我要求解决这个问题。除了这个错误:对于py3k
C\u文件
将是int
,对于py2k,它将是文件*
@mcepl您介意编辑答案以使其正确吗?我相信正确的答案在我上面的解决方案中。
#if PY_MAJOR_VERSION >= 3
if (PyObject_HasAttrString(pyfile, "fileno")) {
int fd = (int)PyLong_AsLong(PyObject_CallMethod(pyfile, "fileno", NULL));
if (PyObject_HasAttrString(pyfile, "mode")) {
char *mode = PyUnicode_AsUTF8AndSize(
PyObject_CallMethod(pyfile, "mode", NULL), NULL);
fp = fdopen(fd, mode);
}
else {
return PyErr_Format(PyExc_ValueError,
"File doesn’t have mode attribute!");
}
}
else {
return PyErr_Format(PyExc_ValueError,
"File doesn’t have fileno method!");
}
#else
fp = PyFile_AsFile(pyfile);
#endif