刚看到这个标题的时候,大家会觉得比较奇怪,nodejs是一门脚本语言,它又没有“指针”这个数据结构,怎么能得到指针呢 ?这个问题关键就是nodejs中的Buffers这个数据结构。
背景
自己做的一个项目需要是从网站上下载一个图片,然后用libjpeg这个C类库对图像进行操作。程序架构是用nodejs写一个主运行程序,用C++扩展来调用libjpeg类库并实现底层的算法。libjpeg的8d版本中已经有两个接口解析图片信息,分别是从文件中读取和从内存中读取。
EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile));
EXTERN(void) jpeg_mem_src JPP((j_decompress_ptr cinfo,
unsigned char * inbuffer,
unsigned long insize));
对应这两个接口,就有两套解决方案:1,先将图片下载到本地文件,然后再从本地文件读到内存; 2,直接将图片读取到本地内存。
显而易见,第二种方案更优:节省了大量的磁盘IO,提升速度。那接下来的问题就是如何写nodejs的C++扩展,得到一块内存指针,这就需要buffers出马了。
解决方案
开始具体的解决方案之前需要先了解如何编写nodejs的C/C++扩展,还是比较简单的。没做过相关开发的同学可以参看以下文章:
1. [nodejs C/C++ Addon][1]
2. [编写nodejs原生扩展][2]
3. [node-extension-examples][3]
nodejs中buffers是一个比较重要的数据结构,典型应用就是读取文件内容和发送http请求,它们都能到相关buffers。查看nodejs的源码就会发现有这样的api:
static inline char* Data(v8::Handle<v8::Object> obj) {
return (char*)obj->GetIndexedPropertiesExternalArrayData();
}
static inline char* Data(Buffer *b) {
return Buffer::Data(b->handle_);
}
static inline size_t Length(v8::Handle<v8::Object> obj) {
return (size_t)obj->GetIndexedPropertiesExternalArrayDataLength();
}
static inline size_t Length(Buffer *b) {
return Buffer::Length(b->handle_);
}
通过Data()函数得到buffer的内存指针,通过Length()得到这块内存的大小,非常有用吧。
这样的话,只要nodejs程序得到buffer,然后转化为v8中的object对象,再从这个object对象中得到这块内存的指针和内存大小,接下来就可以进行想要的指针操作了。重要的代码如下:
Local<Value> arg1 = args[0];
if (Buffer::HasInstance(arg1)) {
size_t size = Buffer::Length(arg1->ToObject());
char* bufferdata = Buffer::Data(arg1->ToObject());
//to do with size and bufferdata
return scope.Close(Number::New(size));
}
else {
return scope.Close(Number::New(-1));
}
完整的代码可以参见:https://github.com/jifeng/node-buffer-extends
其他操作buffer的例子:https://github.com/bnoordhuis/node-buffertools/blob/master/buffertools.cc
sorry,makedown用得不熟练,三篇文章的地址: http://nodejs.org/docs/latest/api/addons.html http://www.grati.org/?p=413 https://github.com/pquerna/node-extension-examples