Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/282.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 ctypes:Python文件对象<-&燃气轮机;C文件*_Python_Ctypes - Fatal编程技术网

Python ctypes:Python文件对象<-&燃气轮机;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

我正在使用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文件*映射可能吗


Joakim

Python文件对象不一定具有底层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