Berkeley DB是Sleepcat开发的开源的嵌入式数据库。具有轻巧、可扩展的优点。
但是它不支持SQL语句,而且操作起来相对比较复杂。
下面讲讲在VC下为了使其能够存储数据结构做的封装。
在google搜索Berkely DB 进入sleepycat下载zip安装包,编译。
建立工程TestBerkeleyDB,拷贝libdb43.dll和libdb43.lib到当前工程下,添加libdb43.dll到工程的setting。
把db.h和db_cxx.h拷贝到当前目录下。
添加icqtypes.h:
#ifndef _ICQ_TYPES_H_
#define _ICQ_TYPES_H_
#include <string>
#include <list>
#include <vector>
#include <bitset>
using namespace std;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned long uint32;
typedef list<string> StrList;
typedef list<void *> PtrList;
typedef list<uint32> UinList;
#endif
添加icqdb.h;
#ifndef _ICQ_DB_H
#define _ICQ_DB_H
#include "icqtypes.h"
#include "db_cxx.h"
#define MAX_BLOCK_SIZE 4096
class DBOutStream {
public:
DBOutStream() {
cursor = data;
}
char *getData() {
return data;
}
int getSize() {
return (cursor - data);
}
DBOutStream &operator <<(uint8 b);
DBOutStream &operator <<(uint16 w);
DBOutStream &operator <<(uint32 dw);
DBOutStream &operator <<(const char *str);
DBOutStream &operator <<(const string &str) {
return operator <<(str.c_str());
}
DBOutStream &operator <<(StrList &strList);
private:
char data[MAX_BLOCK_SIZE];
char *cursor;
};
class DBInStream {
public:
DBInStream(void *d, int n) {
cursor = data = (char *) d;
datalen = n;
}
DBInStream &operator >>(uint8 &b);
DBInStream &operator >>(uint16 &w);
DBInStream &operator >>(uint32 &dw);
DBInStream &operator >>(string &str);
DBInStream &operator >>(StrList &strList);
private:
char *data;
char *cursor;
int datalen;
};
class DBSerialize {
public:
virtual void save(DBOutStream &out) = 0;
virtual void load(DBInStream &in) = 0;
};
#endif
添加icqdb.cpp:
#include "stdafx.h"
#include "icqdb.h"
#include "string.h"
#include "icqtypes.h"
#define INDEX_USER 0
#define INDEX_OPTIONS 0xffffffff
#define INDEX_GROUP 0xfffffffe
DBOutStream &DBOutStream::operator <<(uint8 b)
{
if (cursor <= data + MAX_BLOCK_SIZE - sizeof(b))
*cursor++ = b;
return (*this);
}
DBOutStream &DBOutStream::operator <<(uint16 w)
{
if (cursor <= data + MAX_BLOCK_SIZE - sizeof(w)) {
*(uint16 *) cursor = w;
cursor += sizeof(w);
}
return (*this);
}
DBOutStream &DBOutStream::operator <<(uint32 dw)
{
if (cursor <= data + MAX_BLOCK_SIZE - sizeof(dw)) {
*(uint32 *) cursor = dw;
cursor += sizeof(dw);
}
return (*this);
}
DBOutStream &DBOutStream::operator <<(const char *str)
{
uint16 len = strlen(str) + 1;
if (cursor <= data + MAX_BLOCK_SIZE - sizeof(len) - len) {
*this << len;
memcpy(cursor, str, len);
cursor += len;
}
return (*this);
}
DBOutStream &DBOutStream::operator <<(StrList &strList)
{
uint16 n = 0;
char *old = cursor;
cursor += sizeof(n);
StrList::iterator i;
for (i = strList.begin(); i != strList.end(); i++) {
operator <<(*i);
n++;
}
char *p = cursor;
cursor = old;
operator <<(n);
cursor = p;
return (*this);
}
DBInStream &DBInStream::operator >>(uint8 &b)
{
if (cursor <= data + datalen - sizeof(b))
b = *cursor++;
else
b = 0;
return (*this);
}
DBInStream &DBInStream::operator >>(uint16 &w)
{
if (cursor <= data + datalen - sizeof(w)) {
w = *(uint16 *) cursor;
cursor += sizeof(w);
} else
w = 0;
return (*this);
}
DBInStream &DBInStream::operator >>(uint32 &dw)
{
if (cursor <= data + datalen - sizeof(dw)) {
dw = *(uint32 *) cursor;
cursor += sizeof(dw);
} else
dw = 0;
return (*this);
}
DBInStream &DBInStream::operator >>(string &str)
{
uint16 len;
operator >>(len);
if (cursor <= data + datalen - len && !cursor[len - 1]) {
str = cursor;
cursor += len;
} else
str = "";
return (*this);
}
DBInStream &DBInStream::operator >>(StrList &strList)
{
uint16 num;
operator >>(num);
int n = (int) num;
strList.clear();
while (n-- > 0) {
string s;
operator >>(s);
strList.push_back(s);
}
return (*this);
}
添加CPerson类:
CPerson.h:
// Person.h: interface for the CPerson class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_PERSON_H__D259A8B7_7ACB_4624_8C9E_394B11FFA5C9__INCLUDED_)
#define AFX_PERSON_H__D259A8B7_7ACB_4624_8C9E_394B11FFA5C9__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "icqdb.h"
class CPerson: public DBSerialize
{
public:
CPerson();
virtual ~CPerson();
public:
string Name;
uint16 age;
string Describe;
void save(DBOutStream &out);
void load(DBInStream &in);
};
#endif // !defined(AFX_PERSON_H__D259A8B7_7ACB_4624_8C9E_394B11FFA5C9__INCLUDED_)
Person.cpp:
// Person.cpp: implementation of the CPerson class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "TestBerkeleyDB.h"
#include "Person.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CPerson::CPerson()
{
}
CPerson::~CPerson()
{
}
void CPerson::save(DBOutStream &out)
{
out << Name << age << Describe;
}
void CPerson::load(DBInStream &in)
{
in >> Name >> age >> Describe;
}
下面是主函数:
// TestBerkeleyDB.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "TestBerkeleyDB.h"
#include "db_cxx.h"
#include "icqtypes.h"
#include "icqdb.h"
#include "Person.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// The one and only application object
CWinApp theApp;
//using namespace std;
bool delPeople(char *fileName, string index)
{
Db db(NULL, 0); // Instantiate the Db object
u_int32_t oFlags = DB_CREATE; // Open flags;
try {
// Open the database
db.open(NULL, // Transaction pointer
fileName, // Database file name
NULL, // Optional logical database name
DB_BTREE, // Database access method
oFlags, // Open flags
0); // File mode (using defaults)
// DbException is not subclassed from std::exception, so
// need to catch both of these.
} catch(DbException &e) {
// Error handling code goes here
} catch(std::exception &e) {
// Error handling code goes here
}
Dbc *cursorp;
try {
// Database open omitted
// Get the cursor
db.cursor(NULL, &cursorp, 0);
// Set up our DBTs
Dbt data;
Dbt key;
key.set_data((void*)index.c_str());
key.set_size(index.length()+1);
// Iterate over the database, deleting each record in turn.
int ret;
while ((ret = cursorp->get(&key, &data,
DB_SET)) == 0) {
cursorp->del(0);
}
} catch(DbException &e) {
db.err(e.get_errno(), "Error!");
} catch(std::exception &e) {
db.errx("Error! %s", e.what());
}
// Cursors must be closed
if (cursorp != NULL)
cursorp->close();
db.close(0);
return true;
}
bool delPeople(char *fileName, uint32 index)
{
Db db(NULL, 0); // Instantiate the Db object
u_int32_t oFlags = DB_CREATE; // Open flags;
try {
// Open the database
db.open(NULL, // Transaction pointer
fileName, // Database file name
NULL, // Optional logical database name
DB_BTREE, // Database access method
oFlags, // Open flags
0); // File mode (using defaults)
// DbException is not subclassed from std::exception, so
// need to catch both of these.
} catch(DbException &e) {
// Error handling code goes here
} catch(std::exception &e) {
// Error handling code goes here
}
Dbc *cursorp;
try {
// Database open omitted
// Get the cursor
db.cursor(NULL, &cursorp, 0);
// Set up our DBTs
Dbt data;
Dbt key;
key.set_data(&index);
key.set_size(sizeof(index));
// Iterate over the database, deleting each record in turn.
int ret;
while ((ret = cursorp->get(&key, &data,
DB_SET)) == 0) {
cursorp->del(0);
}
} catch(DbException &e) {
db.err(e.get_errno(), "Error!");
} catch(std::exception &e) {
db.errx("Error! %s", e.what());
}
// Cursors must be closed
if (cursorp != NULL)
cursorp->close();
db.close(0);
return true;
}
bool loadPeople(char *fileName, uint32 index, DBSerialize &obj)
{
Db db(NULL, 0); // Instantiate the Db object
u_int32_t oFlags = DB_CREATE; // Open flags;
try {
// Open the database
db.open(NULL, // Transaction pointer
fileName, // Database file name
NULL, // Optional logical database name
DB_BTREE, // Database access method
oFlags, // Open flags
0); // File mode (using defaults)
// DbException is not subclassed from std::exception, so
// need to catch both of these.
} catch(DbException &e) {
// Error handling code goes here
} catch(std::exception &e) {
// Error handling code goes here
}
Dbt key, data;
key.set_data(&index);
key.set_size(sizeof(index));
if (db.get(NULL, &key, &data, 0) != 0) {
db.close(0);
return false;
}
DBInStream in(data.get_data(), data.get_size());
obj.load(in);
db.close(0);
return true;
}
bool loadPeople(char *fileName, string index, DBSerialize &obj)
{
Db db(NULL, 0); // Instantiate the Db object
u_int32_t oFlags = DB_CREATE; // Open flags;
try {
// Open the database
db.open(NULL, // Transaction pointer
fileName, // Database file name
NULL, // Optional logical database name
DB_BTREE, // Database access method
oFlags, // Open flags
0); // File mode (using defaults)
// DbException is not subclassed from std::exception, so
// need to catch both of these.
} catch(DbException &e) {
// Error handling code goes here
} catch(std::exception &e) {
// Error handling code goes here
}
Dbt key, data;
key.set_data((void*)index.c_str());
key.set_size(index.length()+1);
if (db.get(NULL, &key, &data, 0) != 0) {
db.close(0);
return false;
}
DBInStream in(data.get_data(), data.get_size());
obj.load(in);
db.close(0);
return true;
}
bool savePeople(char *fileName, uint32 index, DBSerialize &obj)
{
Db db(NULL, 0); // Instantiate the Db object
u_int32_t oFlags = DB_CREATE; // Open flags;
try {
// Open the database
db.open(NULL, // Transaction pointer
fileName, // Database file name
NULL, // Optional logical database name
DB_BTREE, // Database access method
oFlags, // Open flags
0); // File mode (using defaults)
// DbException is not subclassed from std::exception, so
// need to catch both of these.
} catch(DbException &e) {
// Error handling code goes here
} catch(std::exception &e) {
// Error handling code goes here
}
DBOutStream out;
obj.save(out);
Dbt key, data;
key.set_data(&index);
key.set_size(sizeof(index));
data.set_data(out.getData());
data.set_size(out.getSize());
int ret = db.put(NULL, &key, &data, 0) ;
db.close(0);
return (ret == 0);
}
bool savePeople(char *fileName, string index, DBSerialize &obj)
{
Db db(NULL, 0); // Instantiate the Db object
u_int32_t oFlags = DB_CREATE; // Open flags;
try {
// Open the database
db.open(NULL, // Transaction pointer
fileName, // Database file name
NULL, // Optional logical database name
DB_BTREE, // Database access method
oFlags, // Open flags
0); // File mode (using defaults)
// DbException is not subclassed from std::exception, so
// need to catch both of these.
} catch(DbException &e) {
// Error handling code goes here
} catch(std::exception &e) {
// Error handling code goes here
}
DBOutStream out;
obj.save(out);
Dbt key, data;
key.set_data((void*)index.c_str());
key.set_size(index.length()+1);
data.set_data(out.getData());
data.set_size(out.getSize());
int ret = db.put(NULL, &key, &data, 0);
db.close(0);
return (ret == 0);
}
bool printAllPeople(char *fileName)
{
Db db(NULL, 0); // Instantiate the Db object
u_int32_t oFlags = DB_CREATE; // Open flags;
try {
// Open the database
db.open(NULL, // Transaction pointer
fileName, // Database file name
NULL, // Optional logical database name
DB_BTREE, // Database access method
oFlags, // Open flags
0); // File mode (using defaults)
// DbException is not subclassed from std::exception, so
// need to catch both of these.
} catch(DbException &e) {
// Error handling code goes here
} catch(std::exception &e) {
// Error handling code goes here
}
Dbc *cursorp;
try {
// Database open omitted
// Get the cursor
db.cursor(NULL, &cursorp, 0);
// Set up our DBTs
Dbt data;
Dbt key;
// Iterate over the database, deleting each record in turn.
int ret;
while ((ret = cursorp->get(&key, &data,
DB_NEXT)) == 0) {
//cursorp->del(0);
CPerson p;
DBInStream in(data.get_data(), data.get_size());
p.load(in);
printf("%s\n",p.Describe);
}
} catch(DbException &e) {
db.err(e.get_errno(), "Error!");
} catch(std::exception &e) {
db.errx("Error! %s", e.what());
}
// Cursors must be closed
if (cursorp != NULL)
cursorp->close();
db.close(0);
return true;
}
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
// initialize MFC and print and error on failure
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
cerr << _T("Fatal Error: MFC initialization failed") << endl;
nRetCode = 1;
}
else
{
string index1 = "Liang Zhijian";
string index2 = "Zou Dan";
CPerson p1;
p1.age = 0;
p1.Name = "Liang Zhijian";
p1.Describe = "student1";
savePeople("mydb.db",index1,p1);
CPerson p2;
p2.age = 1;
p2.Name = "Zou Dan";
p2.Describe = "student2";
savePeople("mydb.db",index2,p2);
CPerson p3;
loadPeople("mydb.db","Liang Zhijian",p3);
printf("%s\n",p3.Describe);
printAllPeople("mydb.db");
delPeople("mydb.db","Liang Zhijian");
printAllPeople("mydb.db");
}
return nRetCode;
}