使用C语言扩展Python(五)

本文探讨了在Python与C扩展模块之间通过文件对象而非文件指针进行数据交互的方法,旨在实现更高效、面向对象的文件操作流程。通过定义Python类并将其实例作为C模块的输入参数,使得数据写入过程更加灵活且易于管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇中我们在python端的做法是每次读取一个数据块,然后将这个数据块传递进C扩展模块中去,但对于目标文件的数据写入是在C扩展模块中完成的,但其实可以更面向对象一点,不是吗?原来outfp是一个文件指针,
不如改成一个从Python中传递一个文件对象到C模块里去,这个文件对象有自己的write方法,这样在C扩展模块中你就可以回调文件对象的write方法来完成数据的写入。
首先来看Python端的代码,我们定义了一个file类继承下来的MyFile子类,其中的write方法就是为在C扩展模块中回调而专门准备的。
ExpandedBlockStart.gif代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->#!/usr/bin/envpython

importclame

INBUFSIZE
=4096

classMyFile(file):

def__init__(self,path,mode):
file.
__init__(self,path,mode)
self.n
=0

defwrite(self,s):
file.write(self,s)
self.n
+=1

output
=MyFile('test3.mp3','wb')
encoder
=clame.Encoder(output)
input
=file('test.raw','rb')

data
=input.read(INBUFSIZE)
whiledata!='':
encoder.encode(data)
data
=input.read(INBUFSIZE)

input.close()
encoder.close()
output.close()

print'output.writewascalled%dtimes'%output.n

再来看C模块的代码,clame_EncoderObject结构体中的outfp改成了PyObject类型的指针,相应的dealloc方法也做了调整,由于outfp是一个对象,因此需要对其引用计数进行减1操作,而以前的代码是直接调用fclose来直接关闭打开的目标文件。但现在我们只需要对其引用计数做减1操作,等到其为0的时候,在外部的python代码中就可以关闭这个文件对象。同样可以看到在init函数中有相应的引用计数加1的操作。在encode和close两个函数中,通过PyObject_CallMethod实现了对Python对象中指定方法的回调。

ExpandedBlockStart.gif代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->#include<Python.h>

#include
<lame.h>

/*
*OnLinux:
*gcc-shared-I/usr/include/python2.6-I/usr/local/include/lameclame.c/
*-lmp3lame-oclame.so
*
*
*/

typedef
struct{
PyObject_HEAD
PyObject
*outfp;
lame_global_flags
*gfp;
}clame_EncoderObject;

staticPyObject*Encoder_new(PyTypeObject*type,PyObject*args,PyObject*kw){
clame_EncoderObject
*self=(clame_EncoderObject*)type->tp_alloc(type,0);
self
->outfp=NULL;
self
->gfp=NULL;
return(PyObject*)self;
}

staticvoidEncoder_dealloc(clame_EncoderObject*self){
if(self->gfp){
lame_close(self
->gfp);
}
Py_XDECREF(self
->outfp);
self
->ob_type->tp_free(self);
}

staticintEncoder_init(clame_EncoderObject*self,PyObject*args,PyObject*kw){
PyObject
*outfp;
if(!PyArg_ParseTuple(args,"O",&outfp)){
return-1;
}
if(self->outfp||self->gfp){
PyErr_SetString(PyExc_Exception,
"__init__alreadycalled");
return-1;
}
self
->outfp=outfp;
Py_INCREF(self
->outfp);
self
->gfp=lame_init();
lame_init_params(self
->gfp);
return0;
}

staticPyObject*Encoder_encode(clame_EncoderObject*self,PyObject*args){
char*in_buffer;
intin_length;
intmp3_length;
char*mp3_buffer;
intmp3_bytes;
if(!(self->outfp&&self->gfp)){
PyErr_SetString(PyExc_Exception,
"encodernotopen");
returnNULL;
}
if(!PyArg_ParseTuple(args,"s#",&in_buffer,&in_length)){
returnNULL;
}
in_length
/=2;
mp3_length
=(int)(1.25*in_length)+7200;
mp3_buffer
=(char*)malloc(mp3_length);
if(in_length>0){
mp3_bytes
=lame_encode_buffer_interleaved(
self
->gfp,
(
short*)in_buffer,
in_length
/2,
mp3_buffer,
mp3_length
);
if(mp3_bytes>0){
PyObject
*write_result=PyObject_CallMethod(
self
->outfp,"write","(s#)",mp3_buffer,mp3_bytes);
if(!write_result){
free(mp3_buffer);
returnNULL;
}
Py_DECREF(write_result);
}
}
free(mp3_buffer);
Py_RETURN_NONE;
}

staticPyObject*Encoder_close(clame_EncoderObject*self){
intmp3_length;
char*mp3_buffer;
intmp3_bytes;
if(!(self->outfp&&self->gfp)){
PyErr_SetString(PyExc_Exception,
"encodernotopen");
returnNULL;
}
mp3_length
=7200;
mp3_buffer
=(char*)malloc(mp3_length);
mp3_bytes
=lame_encode_flush(self->gfp,mp3_buffer,sizeof(mp3_buffer));
if(mp3_bytes>0){
PyObject
*write_result=PyObject_CallMethod(
self
->outfp,"write","(s#)",mp3_buffer,mp3_bytes);
if(!write_result){
free(mp3_buffer);
returnNULL;
}
Py_DECREF(write_result);
}
free(mp3_buffer);
lame_close(self
->gfp);
self
->gfp=NULL;
self
->outfp=NULL;
Py_RETURN_NONE;
}

staticPyMethodDefEncoder_methods[]={
{
"encode",(PyCFunction)Encoder_encode,METH_VARARGS,
"Encodesandwritesdatatotheoutputfile."},
{
"close",(PyCFunction)Encoder_close,METH_NOARGS,
"Closestheoutputfile."},
{NULL,NULL,
0,NULL}
};

staticPyTypeObjectclame_EncoderType={
PyObject_HEAD_INIT(NULL)
0,/*ob_size*/
"clame.Encoder",/*tp_name*/
sizeof(clame_EncoderObject),/*tp_basicsize*/
0,/*tp_itemsize*/
(destructor)Encoder_dealloc,
/*tp_dealloc*/
0,/*tp_print*/
0,/*tp_getattr*/
0,/*tp_setattr*/
0,/*tp_compare*/
0,/*tp_repr*/
0,/*tp_as_number*/
0,/*tp_as_sequence*/
0,/*tp_as_mapping*/
0,/*tp_hash*/
0,/*tp_call*/
0,/*tp_str*/
0,/*tp_getattro*/
0,/*tp_setattro*/
0,/*tp_as_buffer*/
Py_TPFLAGS_DEFAULT,
/*tp_flags*/
"Myfirstencoderobject.",/*tp_doc*/
0,/*tp_traverse*/
0,/*tp_clear*/
0,/*tp_richcompare*/
0,/*tp_weaklistoffset*/
0,/*tp_iter*/
0,/*tp_iternext*/
Encoder_methods,
/*tp_methods*/
0,/*tp_members*/
0,/*tp_getset*/
0,/*tp_base*/
0,/*tp_dict*/
0,/*tp_descr_get*/
0,/*tp_descr_set*/
0,/*tp_dictoffset*/
(initproc)Encoder_init,
/*tp_init*/
0,/*tp_alloc*/
Encoder_new,
/*tp_new*/
0,/*tp_free*/
};

staticPyMethodDefclame_methods[]={
{NULL,NULL,
0,NULL}
};

PyMODINIT_FUNCinitclame(){
PyObject
*m;
if(PyType_Ready(&clame_EncoderType)<0){
return;
}
m
=Py_InitModule3("clame",clame_methods,"MythirdLAMEmodule.");
Py_INCREF(
&clame_EncoderType);
PyModule_AddObject(m,
"Encoder",(PyObject*)&clame_EncoderType);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值