LevelDB C 迭代器
LevelDB C iterator
我需要用 c 语言遍历 leveldb 数据库 - https://github.com/google/leveldb/blob/master/include/leveldb/c.h。一切正常,除了 iterating.The 结果带有一些二进制噪声数据:
key: value1
key: value2
key#&^$&*# value
one1(*@(# value1
two2%*@( value2
用$&*#等符号我显示的是二进制输出,Whosebug不允许在这里放二进制输出。
代码:
#include <leveldb/c.h>
#include <stdio.h>
int main() {
leveldb_t *db;
leveldb_options_t *options;
leveldb_readoptions_t *roptions;
leveldb_writeoptions_t *woptions;
char *err = NULL;
char *read;
size_t read_len;
/******************************************/
/* OPEN */
options = leveldb_options_create();
leveldb_options_set_create_if_missing(options, 1);
db = leveldb_open(options, "testdb", &err);
if (err != NULL) {
fprintf(stderr, "Open fail.\n");
return(1);
}
/* reset error var */
leveldb_free(err); err = NULL;
/******************************************/
/* WRITE */
woptions = leveldb_writeoptions_create();
leveldb_put(db, woptions, "one", 3, "value1", 6, &err);
if (err != NULL) {
fprintf(stderr, "Write fail.\n");
return(1);
}
leveldb_free(err); err = NULL;
/******************************************/
/* WRITE 2 */
woptions = leveldb_writeoptions_create();
leveldb_put(db, woptions, "two", 3, "value2", 6, &err);
if (err != NULL) {
fprintf(stderr, "Write fail.\n");
return(1);
}
leveldb_free(err); err = NULL;
/******************************************/
/* READ */
roptions = leveldb_readoptions_create();
read = leveldb_get(db, roptions, "one", 3, &read_len, &err);
if (err != NULL) {
fprintf(stderr, "Read fail.\n");
return(1);
}
printf("key: %s\n", read);
leveldb_free(err); err = NULL;
/******************************************/
/* READ 2 */
roptions = leveldb_readoptions_create();
read = leveldb_get(db, roptions, "two", 3, &read_len, &err);
if (err != NULL) {
fprintf(stderr, "Read fail.\n");
return(1);
}
printf("key: %s\n", read);
leveldb_free(err); err = NULL;
/******************************************/
/* ITERATE */
roptions = leveldb_readoptions_create();
leveldb_iterator_t *iter = leveldb_create_iterator(db, roptions);
for (leveldb_iter_seek_to_first(iter); leveldb_iter_valid(iter); leveldb_iter_next(iter))
{
size_t key_len, value_len;
const char *key_ptr = leveldb_iter_key(iter, &key_len);
const char *value_ptr = leveldb_iter_value(iter, &value_len);
/* Prints some binary noise with the data */
printf("%s %s\n", key_ptr, value_ptr);
}
leveldb_iter_destroy(iter);
leveldb_free(err); err = NULL;
/******************************************/
/* CLOSE */
leveldb_close(db);
return(0);
}
如何在 C 中正确地遍历 LevelDB?
leveldb_iter_key
和 leveldb_iter_value
返回的值似乎不是正确的以 NULL 结尾的字符串。
所以,肮脏的解决方案是使用
printf("%.*s %.*s\n", (int) key_len, key_ptr, (int) value_len, value_ptr);
而不是
printf("%s %s\n", key_ptr, value_ptr);
但是,IMO 最好根据它们的长度复制这些值然后使用它们。
如您在 https://github.com/google/leveldb/blob/master/db/c.cc#L197 中所见,leveldb_get
创建适当长度的切片(Slice(key, keylen)
在 L205 上)和 returns 密钥副本(CopyString
在 L208)。
补充:
我已经用 valgrind 检查了你的代码,选项有一些内存泄漏。您应该手动释放它们(例如 leveldb_writeoptions_destroy
对应 woptions
)。 leveldb_get
个结果 (read
) 也应该被释放。
示例代码:
// allocate new strings
char * key = (char *) malloc(key_len + 1);
char * value = (char *) malloc(value_len + 1);
// copy string content and ensure that string is null-terminated
memcpy(key, key_ptr, key_len);
key[key_len] = 0;
memcpy(value, value_ptr, value_len);
value[value_len] = 0;
// print
printf("%s %s\n", key, value);
// free
free(key);
free(value);
LevelDB 不使用 C(++) 字符串作为键和值,它使用可能包含 NUL 且不以 NUL 结尾的字节数组。这记录在这里:1.
使用任何面向字符串的 C 函数来操作这些数组都是错误的。您可以不使用printf
来安全地显示返回值。
我需要用 c 语言遍历 leveldb 数据库 - https://github.com/google/leveldb/blob/master/include/leveldb/c.h。一切正常,除了 iterating.The 结果带有一些二进制噪声数据:
key: value1
key: value2
key#&^$&*# value
one1(*@(# value1
two2%*@( value2
用$&*#等符号我显示的是二进制输出,Whosebug不允许在这里放二进制输出。
代码:
#include <leveldb/c.h>
#include <stdio.h>
int main() {
leveldb_t *db;
leveldb_options_t *options;
leveldb_readoptions_t *roptions;
leveldb_writeoptions_t *woptions;
char *err = NULL;
char *read;
size_t read_len;
/******************************************/
/* OPEN */
options = leveldb_options_create();
leveldb_options_set_create_if_missing(options, 1);
db = leveldb_open(options, "testdb", &err);
if (err != NULL) {
fprintf(stderr, "Open fail.\n");
return(1);
}
/* reset error var */
leveldb_free(err); err = NULL;
/******************************************/
/* WRITE */
woptions = leveldb_writeoptions_create();
leveldb_put(db, woptions, "one", 3, "value1", 6, &err);
if (err != NULL) {
fprintf(stderr, "Write fail.\n");
return(1);
}
leveldb_free(err); err = NULL;
/******************************************/
/* WRITE 2 */
woptions = leveldb_writeoptions_create();
leveldb_put(db, woptions, "two", 3, "value2", 6, &err);
if (err != NULL) {
fprintf(stderr, "Write fail.\n");
return(1);
}
leveldb_free(err); err = NULL;
/******************************************/
/* READ */
roptions = leveldb_readoptions_create();
read = leveldb_get(db, roptions, "one", 3, &read_len, &err);
if (err != NULL) {
fprintf(stderr, "Read fail.\n");
return(1);
}
printf("key: %s\n", read);
leveldb_free(err); err = NULL;
/******************************************/
/* READ 2 */
roptions = leveldb_readoptions_create();
read = leveldb_get(db, roptions, "two", 3, &read_len, &err);
if (err != NULL) {
fprintf(stderr, "Read fail.\n");
return(1);
}
printf("key: %s\n", read);
leveldb_free(err); err = NULL;
/******************************************/
/* ITERATE */
roptions = leveldb_readoptions_create();
leveldb_iterator_t *iter = leveldb_create_iterator(db, roptions);
for (leveldb_iter_seek_to_first(iter); leveldb_iter_valid(iter); leveldb_iter_next(iter))
{
size_t key_len, value_len;
const char *key_ptr = leveldb_iter_key(iter, &key_len);
const char *value_ptr = leveldb_iter_value(iter, &value_len);
/* Prints some binary noise with the data */
printf("%s %s\n", key_ptr, value_ptr);
}
leveldb_iter_destroy(iter);
leveldb_free(err); err = NULL;
/******************************************/
/* CLOSE */
leveldb_close(db);
return(0);
}
如何在 C 中正确地遍历 LevelDB?
leveldb_iter_key
和 leveldb_iter_value
返回的值似乎不是正确的以 NULL 结尾的字符串。
所以,肮脏的解决方案是使用
printf("%.*s %.*s\n", (int) key_len, key_ptr, (int) value_len, value_ptr);
而不是
printf("%s %s\n", key_ptr, value_ptr);
但是,IMO 最好根据它们的长度复制这些值然后使用它们。
如您在 https://github.com/google/leveldb/blob/master/db/c.cc#L197 中所见,leveldb_get
创建适当长度的切片(Slice(key, keylen)
在 L205 上)和 returns 密钥副本(CopyString
在 L208)。
补充:
我已经用 valgrind 检查了你的代码,选项有一些内存泄漏。您应该手动释放它们(例如 leveldb_writeoptions_destroy
对应 woptions
)。 leveldb_get
个结果 (read
) 也应该被释放。
示例代码:
// allocate new strings
char * key = (char *) malloc(key_len + 1);
char * value = (char *) malloc(value_len + 1);
// copy string content and ensure that string is null-terminated
memcpy(key, key_ptr, key_len);
key[key_len] = 0;
memcpy(value, value_ptr, value_len);
value[value_len] = 0;
// print
printf("%s %s\n", key, value);
// free
free(key);
free(value);
LevelDB 不使用 C(++) 字符串作为键和值,它使用可能包含 NUL 且不以 NUL 结尾的字节数组。这记录在这里:1.
使用任何面向字符串的 C 函数来操作这些数组都是错误的。您可以不使用printf
来安全地显示返回值。