官网链接-unqlite_kv_fetch_callback
关于unqlite_kv_cursor_key和unqlite_kv_cursor_key_callback
int unqlite_kv_cursor_key(unqlite_kv_cursor *pCursor, void *pBuf, int *pnByte)
{
int rc;
#ifdef UNTRUST
if (pCursor == 0) {
return UNQLITE_CORRUPT;
}
#endif
if (pBuf == 0) {
/* Key length only */
rc = pCursor->pStore->pIo->pMethods->xKeyLength(pCursor, pnByte);
}
else {
SyBlob sBlob;
if ((*pnByte) < 0) {
return UNQLITE_CORRUPT;
}
/* Initialize the data consumer */
SyBlobInitFromBuf(&sBlob, pBuf, (sxu32)(*pnByte));
/* Consume the key */
rc = pCursor->pStore->pIo->pMethods->xKey(pCursor, unqliteDataConsumer, &sBlob);
/* Key length */
*pnByte = SyBlobLength(&sBlob);
/* Cleanup */
SyBlobRelease(&sBlob);
}
return rc;
}
unqlite_kv_cursor_key源码如上,实现将pCursor
对应的key值写到pBuf
中。需要注意的是,该函数一开始执行判断if (pBuf == 0)
,然后将key值长度写到pnByte
,如果pBuf!=0
接着判断if ((*pnByte) < 0)
,这时才会把key值写到pBuf
。也就是说,对pBuf
和pnByte
的写是分开的,如果传进来的pnByte
没初始化,那么后面对pBuf
的写就会出现错误(实际就是不会写)。因此,为了保证正确写pBuf
,建议先传0
到该函数以获取key值长度到pnByte
,再来写pBuf
。如下。
unqlite_kv_cursor_key(pCur_name, 0, &nKeyLen); // Extract key length
unqlite_kv_cursor_key(pCur_name, num, &nKeyLen); // consume the key
int unqlite_kv_cursor_key_callback(unqlite_kv_cursor *pCursor, int(*xConsumer)(const void *, unsigned int, void *), void *pUserData)
{
int rc;
#ifdef UNTRUST
if (pCursor == 0) {
return UNQLITE_CORRUPT;
}
#endif
/* Consume the key directly */
rc = pCursor->pStore->pIo->pMethods->xKey(pCursor, xConsumer, pUserData);
return rc;
}
demo里使用回调函数DataConsumerCallback
,将key值定向到标准输出STD_OUTPUT_HANDLE
。
unqlite_kv_cursor_key_callback(pCur_name, DataConsumerCallback, 0);
static int DataConsumerCallback(const void *pData, unsigned int nDatalen, void *pUserData /* Unused */)
{
#ifdef __WINNT__
BOOL rc;
rc = WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), pData, (DWORD)nDatalen, 0, 0);
if (!rc) {
/* Abort processing */
return UNQLITE_ABORT;
}
#else
ssize_t nWr;
nWr = write(STDOUT_FILENO, pData, nDatalen);
if (nWr < 0) {
/* Abort processing */
return UNQLITE_ABORT;
}
#endif /* __WINT__ */
/* All done, data was redirected to STDOUT */
return UNQLITE_OK;
}
其中的注释值得关注,下面单独列出。
/*
* Data consumer callback [unqlite_kv_fetch_callback(), unqlite_kv_cursor_key_callback(), etc.).
*
* Rather than allocating a static or dynamic buffer (Inefficient scenario for large data).
* The caller simply need to supply a consumer callback which is responsible of consuming
* the record data perhaps redirecting it (i.e. Record data) to its standard output (STDOUT),
* disk file, connected peer and so forth.
* Depending on how large the extracted data, the callback may be invoked more than once.
*/
这个注释非常非常关键,使用回调函数重定向数据到标准输出、磁盘文件、connected peer等,相比于上一种方法将数据写到pBuf
,回调函数在处理大数据方面会更加高效
当然,也可以使用回调函数将数据写道指定的buff中来,不过这样就得不偿失了。如下,提供一种思路。稍微修改函数DataConsumerCallback
。
#ifdef __WINNT__
BOOL rc;
rc = WriteFile(GetStdHandle(IGNORE), pData, (DWORD)nDatalen, 0, 0);
strcpy_s((char *)pUserData, nDatalen, (char *)pData);
if (!rc) {
/* Abort processing */
return UNQLITE_ABORT;
}
unqlite_kv_cursor_key_callback(pCur_name, DataConsumerCallback, num);
将key值写到num
。