Python Cookbook(第3版)中文版:15.19 从C语言中读取类文件对象
15.19 从C语言中读取类文件对象¶
问题¶
你要写C扩展来读取来自任何Python类文件对象中的数据(比如普通文件、StringIO对象等)。
解决方案¶
要读取一个类文件对象的数据,你需要重复调用 read() 方法,然后正确的解码获得的数据。
下面是一个C扩展函数例子,仅仅只是读取一个类文件对象中的所有数据并将其输出到标准输出:
#define CHUNK_SIZE 8192 /* Consume a "file-like" object and write bytes to stdout */
static PyObject *py_consume_file(PyObject *self, PyObject *args) {
PyObject *obj;
PyObject *read_meth;
PyObject *result = NULL;
PyObject *read_args; if (!PyArg_ParseTuple(args,"O", &obj)) {
return NULL;
} /* Get the read method of the passed object */
if ((read_meth = PyObject_GetAttrString(obj, "read")) == NULL) {
return NULL;
} /* Build the argument list to read() */
read_args = Py_BuildValue("(i)", CHUNK_SIZE);
while (1) {
PyObject *data;
PyObject *enc_data;
char *buf;
Py_ssize_t len; /* Call read() */
if ((data = PyObject_Call(read_meth, read_args, NULL)) == NULL) {
goto final;
} /* Check for EOF */
if (PySequence_Length(data) == 0) {
Py_DECREF(data);
break;
} /* Encode Unicode as Bytes for C */
if ((enc_data=PyUnicode_AsEncodedString(data,"utf-8","strict"))==NULL) {
Py_DECREF(data);
goto final;
} /* Extract underlying buffer data */
PyBytes_AsStringAndSize(enc_data, &buf, &len); /* Write to stdout (replace with something more useful) */
write(1, buf, len); /* Cleanup */
Py_DECREF(enc_data);
Py_DECREF(data);
}
result = Py_BuildValue(""); final:
/* Cleanup */
Py_DECREF(read_meth);
Py_DECREF(read_args);
return result;
}
要测试这个代码,先构造一个类文件对象比如一个StringIO实例,然后传递进来:
>>> import io
>>> f = io.StringIO('Hello\nWorld\n')
>>> import sample
>>> sample.consume_file(f)
Hello
World
>>>
讨论¶
和普通系统文件不同的是,一个类文件对象并不需要使用低级文件描述符来构建。
因此,你不能使用普通的C库函数来访问它。
你需要使用Python的C API来像普通文件类似的那样操作类文件对象。
在我们的解决方案中,read() 方法从被传递的对象中提取出来。
一个参数列表被构建然后不断的被传给 PyObject_Call() 来调用这个方法。
要检查文件末尾(EOF),使用了 PySequence_Length() 来查看是否返回对象长度为0.
对于所有的I/O操作,你需要关注底层的编码格式,还有字节和Unicode之前的区别。
本节演示了如何以文本模式读取一个文件并将结果文本解码为一个字节编码,这样在C中就可以使用它了。
如果你想以二进制模式读取文件,只需要修改一点点即可,例如:
...
/* Call read() */
if ((data = PyObject_Call(read_meth, read_args, NULL)) == NULL) {
goto final;
} /* Check for EOF */
if (PySequence_Length(data) == 0) {
Py_DECREF(data);
break;
}
if (!PyBytes_Check(data)) {
Py_DECREF(data);
PyErr_SetString(PyExc_IOError, "File must be in binary mode");
goto final;
} /* Extract underlying buffer data */
PyBytes_AsStringAndSize(data, &buf, &len);
...
本节最难的地方在于如何进行正确的内存管理。
当处理 PyObject * `` 变量的时候,需要注意管理引用计数以及在不需要的变量的时候清理它们的值。 的调用就是来做这个的。
对 ``Py_DECREF()
本节代码以一种通用方式编写,因此他也能适用于其他的文件操作,比如写文件。
例如,要写数据,只需要获取类文件对象的 write() 方法,将数据转换为合适的Python对象
(字节或Unicode),然后调用该方法将输入写入到文件。
最后,尽管类文件对象通常还提供其他方法(比如readline(), read_info()),
我们最好只使用基本的 read() 和 write() 方法。
在写C扩展的时候,能简单就尽量简单。
Python Cookbook(第3版)中文版:15.19 从C语言中读取类文件对象的更多相关文章
- Python Cookbook(第3版)中文版:15.20 处理C语言中的可迭代对象
15.20 处理C语言中的可迭代对象¶ 问题¶ 你想写C扩展代码处理来自任何可迭代对象如列表.元组.文件或生成器中的元素. 解决方案¶ 下面是一个C扩展函数例子,演示了怎样处理可迭代对象中的元素: s ...
- Python Cookbook(第3版)中文版:15.21 诊断分段错误
15.21 诊断分段错误¶ 问题¶ 解释器因为某个分段错误.总线错误.访问越界或其他致命错误而突然间奔溃. 你想获得Python堆栈信息,从而找出在发生错误的时候你的程序运行点. 解决方案¶ faul ...
- Python Cookbook(第3版)中文版:15.18 传递已打开的文件给C扩展
15.18 传递已打开的文件给C扩展¶ 问题¶ 你在Python中有一个打开的文件对象,但是需要将它传给要使用这个文件的C扩展. 解决方案¶ 要将一个文件转换为一个整型的文件描述符,使用 PyFile ...
- Python Cookbook(第3版) 中文版 pdf完整版|网盘下载内附提取码
Python Cookbook(第3版)中文版介绍了Python应用在各个领域中的一些使用技巧和方法,其主题涵盖了数据结构和算法,字符串和文本,数字.日期和时间,迭代器和生成器,文件和I/O,数据编码 ...
- Python Cookbook(第3版)中文版:15.14 传递Unicode字符串给C函数库
15.14 传递Unicode字符串给C函数库¶ 问题¶ 你要写一个扩展模块,需要将一个Python字符串传递给C的某个库函数,但是这个函数不知道该怎么处理Unicode. 解决方案¶ 这里我们需要考 ...
- Python Cookbook(第3版)中文版:15.15 C字符串转换为Python字符串
15.15 C字符串转换为Python字符串¶ 问题¶ 怎样将C中的字符串转换为Python字节或一个字符串对象? 解决方案¶ C字符串使用一对 char * 和 int 来表示, 你需要决定字符串到 ...
- Python Cookbook(第3版)中文版:15.16 不确定编码格式的C字符串
15.16 不确定编码格式的C字符串¶ 问题¶ 你要在C和Python直接来回转换字符串,但是C中的编码格式并不确定. 例如,可能C中的数据期望是UTF-8,但是并没有强制它必须是. 你想编写代码来以 ...
- Python Cookbook(第3版)中文版:15.17 传递文件名给C扩展
15.17 传递文件名给C扩展¶ 问题¶ 你需要向C库函数传递文件名,但是需要确保文件名根据系统期望的文件名编码方式编码过. 解决方案¶ 写一个接受一个文件名为参数的扩展函数,如下这样: static ...
- 实操一下<python cookbook>第三版1
这几天没写代码, 练一下代码. 找的书是<python cookbook>第三版的电子书. *这个操作符,运用得好,确实少很多代码,且清晰易懂. p = (4, 5) x, y = p p ...
随机推荐
- 像我这样优雅地进行Spring整合MongoDB
本文重点是要将mongodb与spring整合到项目中去,在实践中发现问题,追踪问题,然后解决问题. 一.准备 Maven.Spring(spring-data-mongodb) spring Dat ...
- [CQOI2006]凸多边形
很明显是一道半平面交的题. 先说一下半平面交的步骤: 1.用点向法(点+向量)表示直线 2.极角排序,若极角相同,按相对位置排序. 3.去重,极角相同的保留更优的 4.枚举边维护双端队列 5.求答案 ...
- macbook air扩展显示器全屏滑动怎样不一起滑动?
macbook air 外接了一个显示器(扩展),当我有多个桌面时,用手指滑动触控板切换桌面时,扩展屏幕也跟着切换桌面有什么办法能让我在切换主屏幕桌面的时候,扩展屏幕保持不动呢?上周还好好的,昨晚关机 ...
- javascript函数大全
JavaScript函数大全 1.document.write(""); 输出语句2.JS中的注释为//3.传统的HTML文档顺序是:document->html->( ...
- 终极解决方案:java.security.cert.CertificateException: Certificates does not conform to algorithm constraints
报错信息 javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: Certificates does ...
- 初识vue——语法初解
这次我们按照官网上的教程对vue的语法进行一个初步的了解: 一.声明式渲染 Vue.js的核心是一个允许采用简洁的模板语法来声明式的将数据渲染仅DOM的系统: 1.我们在HelloWorld里面输入下 ...
- Yii2中DAO
数据库访问 (DAO) 创建数据库连接 执行 SQL 查询 引用表和列名称 执行事务 复制和读写分离 操纵数据库模式 Yii 包含了一个建立在 PHP PDO 之上的数据访问层 (DAO).DAO为不 ...
- Mysql主从复制_模式之日志点复制
MySQL数据复制的原理 MySQL复制基于主服务器在二进制日志中跟踪所有对数据库的更改(更新.删除等等).因此,要进行复制,必须在主服务器上启用二进制日志. 每个从服务器从主服务器接收主服务器已经记 ...
- python中__name__=='__main__'的作用
学习python语法的过程中碰到了__name__=='__main__',这里做个笔记. 作用 这段代码的作用就是让你写的脚本模块既可以导入到别的模块中用,另外该模块自己也可执行. 测试 先 ...
- Py4j-RPC
python 使用灵活.方便在科研中被广泛的使用,Numpy和SciPy等科学计算库使其拥有强大的计算方式.很多机器学习和深度学习的库也都采用了python,然而在大数据.后台开发中仍然较多的使用Ja ...