这篇文章主要讲解了从C语言中读取Python类文件对象的方法,内容清晰明了,对此有兴趣的小伙伴可以学习一下,相信大家阅读完之后会有帮助。
<强>问题强>
你要写C扩展来读取来自任何Python类文件对象中的数据(比如普通文件,StringIO对象等)。
<强>解决方案
强>
要读取一个类文件对象的数据,你需要重复调用读()方法,然后正确的解码获得的数据。
下面是一个C扩展函数例子,仅仅只是读取一个类文件对象中的所有数据并将其输出到标准输出:
# define CHUNK_SIZE 8192/*消费“file-like"对象和字节写入标准输出*/静态PyObject * py_consume_file (PyObject *自我,PyObject * args) { PyObject * obj; PyObject * read_meth; PyObject *结果=零; PyObject * read_args; 如果(! PyArg_ParseTuple (args,“O",, obj)) { 返回NULL; }/*通过的阅读方法对象*/如果((read_meth=PyObject_GetAttrString (obj,“read"))==NULL) { 返回NULL; }/*建立参数列表阅读()*/read_args=Py_BuildValue(“(我)“,CHUNK_SIZE); 而(1){ PyObject *数据; PyObject * enc_data; char *缓冲区; Py_ssize_t len;/*调用read () */如果((data=https://www.yisu.com/zixun/PyObject_Call (read_meth read_args, NULL))==NULL) { 转到最后; }/*检查EOF */如果(PySequence_Length(数据)==0){ Py_DECREF(数据); 打破; }/* Unicode编码的字节C */如果((enc_data=PyUnicode_AsEncodedString(数据、“utf - 8”、“严格”))==NULL) { Py_DECREF(数据); 转到最后; } *//*提取潜在的缓冲区数据 PyBytes_AsStringAndSize (enc_data缓冲区,len);/*写到stdout(替换为更有用的)*/写(1 buf len);/*清理*/Py_DECREF (enc_data); Py_DECREF(数据); } 结果=Py_BuildValue (" "); 最后:/*清理*/Py_DECREF (read_meth); Py_DECREF (read_args); 返回结果; }
要测试这个代码,先构造一个类文件对象比如一个StringIO实例,然后传递进来:
在祝辞祝辞进口io 在在在f=io.StringIO(& # 39;你好\ nWorld \ n # 39;) 在在在导入样例 在在在sample.consume_file (f) 你好 世界 祝辞祝辞祝辞
<>强讨论强>
和普通系统文件不同的是,一个类文件对象并不需要使用低级文件描述符来构建,因此,你不能使用普通的C库函数来访问它。你需要使用Python的C API来像普通文件类似的那样操作类文件对象。
在我们的解决方案中,<代码>阅读()代码>方法从被传递的对象中提取出来。一个参数列表被构建然后不断的被传给<代码> PyObject_Call() 代码>来调用这个方法。要检查文件末尾(EOF),使用了<代码> PySequence_Length() 代码>来查看是否返回对象长度为0。
对于所有的I/O操作,你需要关注底层的编码格式,还有字节和Unicode之前的区别。本节演示了如何以文本模式读取一个文件并将结果文本解码为一个字节编码,这样在C中就可以使用它了。如果你想以二进制模式读取文件,只需要修改一点点即可,例如:
…/*调用read () */如果((data=https://www.yisu.com/zixun/PyObject_Call (read_meth read_args, NULL))==NULL) { 转到最后; }/*检查EOF */如果(PySequence_Length(数据)==0){ Py_DECREF(数据); 打破; } 如果(! PyBytes_Check(数据)){ Py_DECREF(数据); PyErr_SetString (PyExc_IOError“文件必须在二进制模式”); 转到最后; } *//*提取潜在的缓冲区数据 PyBytes_AsStringAndSize(数据、buf len); …
本节最难的地方在于如何进行正确的内存管理。当处理<代码> PyObject *> 代码变量的时候,需要注意管理引用计数以及在不需要的变量的时候清理它们的值。对<代码> Py_DECREF() 代码>的调用就是来做这个的。
本节代码以一种通用方式编写,因此他也能适用于其他的文件操作,比如写文件,例如,要写数据,只需要获取类文件对象的<代码>写()代码>方法,将数据转换为合适的Python对象(字节或Unicode),然后调用该方法将输入写入到文件。
最后,尽管类文件对象通常还提供其他方法(比如readline (), read_info()),我们最好只使用基本的<代码>阅读()代码>和<代码>写()代码>方法。在写C扩展的时候,能简单就尽量简单。
看完上述内容,是不是对从C语言中读取Python类文件对象的方法有进一步的了解,如果还想学习更多内容,欢迎关注行业资讯频道。