1
using
System;
2
using
System.Collections.Generic;
3
using
System.IO;
4
using
System.Linq;
5
using
System.Runtime.Serialization.Formatters.Binary;
6
using
System.Text;
7
using
BerkeleyDb;
8
using
Component;
9
10
namespace
ToolManager
11
{
12
public class BDBRecord
13
{
14
public object Key { get; set; }
15
public string Value { get; set; }
16
} /// <summary>
17
/// BDB数据库操作类库
18
/// </summary>
19
public class BDBHelper
20
{
21
22
private string DBFilePath { get; set; }
23
private DBStoreType DBType { get; set; }
24
public enum DBStoreType : byte
25
{
26
Auto=1,
27
Queue,
28
Hash
29
}
30
[Obsolete("该构造函数已废弃 ,请使用BDBHelper(string dbfilePath)")]
31
public BDBHelper()
32
{
33
}
34
35
public BDBHelper(string dbfilePath)
36
{
37
this.DBFilePath = dbfilePath;
38
}
39
[Obsolete("该构造函数已废弃 ,请使用BDBHelper(string dbfilePath)")]
40
public BDBHelper(string dbfilePath, DBStoreType type)
41
{
42
this.DBFilePath = dbfilePath;
43
this.DBType = type;
44
}
45
public BDBRecord FindOne()
46
{
47
return this.FindOne(null);
48
}
49
public BDBRecord FindOne(Func<object, string, bool> predicate)
50
{
51
//Dictionary<string, object> dict = new Dictionary<string, object>();
52
try
53
{
54
Queue格式
85
}
86
catch (Exception ex)
87
{
88
Hash格式
121
//}
122
}
123
//return dict;
124
return null;
125
}
126
public Dictionary<object, string> FindAll(Func<object, string, bool> predicate)
127
{
128
129
Dictionary<object, string> dict = new Dictionary<object, string>();
130
try
131
{
132
Queue格式
150
}
151
catch (Exception ex)
152
{
153
Hash格式
173
//}
174
}
175
return dict;
176
}
177
public Dictionary<object, string> FindAll()
178
{
179
//either below works fine
180
//return this.FindAll((s, o) => true);
181
return this.FindAll(null);
182
}
183
private static void _Do(KeyDataPair kvp, Func<object, string, bool> predicate, Dictionary<object, string> result)
184
{
185
BinaryFormatter bf = new BinaryFormatter();
186
MemoryStream stream = new MemoryStream();
187
stream.Write(kvp.Data.Buffer, 0, kvp.Data.Size);
188
stream.Seek(0, SeekOrigin.Begin);
189
string k = Encoding.UTF8.GetString(kvp.Key.Buffer, 0, kvp.Key.Size);
190
object v = bf.Deserialize(stream);
191
if (predicate == null)
192
{
193
result.Add(v, k);
194
}
195
else if (predicate(v, k))
196
{
197
result.Add(v, k);
198
}
199
}
200
private static void _Do2(KeyDataPair kvp, Func<object, string, bool> predicate, Dictionary<object, string> result)
201
{
202
BinaryFormatter bf = new BinaryFormatter();
203
MemoryStream stream = new MemoryStream();
204
stream.Write(kvp.Data.Buffer, 0, kvp.Data.Size);
205
stream.Seek(0, SeekOrigin.Begin);
206
string k = BitConverter.ToInt32(kvp.Key.Buffer, 0).ToString();
207
object v = bf.Deserialize(stream);
208
if (predicate == null)
209
{
210
result.Add(v, k);
211
}
212
else if (predicate(v, k))
213
{
214
result.Add(v, k);
215
}
216
}
217
/// <summary>
218
/// 更新数据库中的数据
219
/// </summary>
220
/// <param name="predicate">execute condition</param>
221
/// <param name="isMatchOnlyOnce">is match only once</param>
222
/// <returns>effect records</returns>
223
public int UpdateInQueueMode(Func<int, object, bool> predicate, object value,bool isMatchOnlyOnce)
224
{
225
int count = 0;
226
if (predicate == null)
227
return 0;
228
//遍历数据
229
using (Db db = new Db(DbCreateFlags.None))
230
{
231
db.RecLen = 5000;
232
db.RecPad = '.';
233
//这里如果应用Db.OpenFlags.Create则在启动后会覆盖同名文件,并新建同名文件
234
//Db.OpenFlags.Truncate会清空数据库
235
DbQueue dbf = (DbQueue)db.Open(null, this.DBFilePath, null, DbType.Queue,
236
Db.OpenFlags.ThreadSafe|Db.OpenFlags.Create, 0);
237
238
using (DbQueueCursor cursor = dbf.OpenCursor(null, DbFileCursor.CreateFlags.None))
239
{
240
BinaryFormatter bf = new BinaryFormatter();
241
MemoryStream stream = new MemoryStream();
242
foreach (KeyDataPair kdp in cursor)
243
{
244
int k = BitConverter.ToInt32(kdp.Key.Buffer, 0);
245
Console.WriteLine("k={0}", k.ToString());
246
stream.SetLength(0);
247
stream.Position = 0;
248
stream.Write(kdp.Data.Buffer, 0, kdp.Data.Size);
249
stream.Seek(0, SeekOrigin.Begin);
250
object v = bf.Deserialize(stream);
251
if(predicate(k,v))
252
{
253
count++;
254
//string d = Encoding.UTF8.GetString(kdp.Data.Buffer, 0, kdp.Data.Size);
255
//如何读取Queue类型的主键值
256
257
258
//Console.WriteLine("{0},{1}", p2.State, p2.Os);
259
//p2.Os = "changed";
260
//stream = new MemoryStream();
261
stream.Position = 0;
262
stream.SetLength(0);
263
bf.Serialize(stream, value);
264
DbEntry data = DbEntry.InOut(stream.ToArray());
265
cursor.Put(ref data);
266
if (isMatchOnlyOnce)
267
{
268
stream.Close();
269
return count;
270
}
271
}
272
}
273
stream.Close();
274
}
275
}
276
return count;
277
}
278
279
public void CreateInQueueMode(object value)
280
{
281
Db PC = new Db(DbCreateFlags.None);
282
PC.RecLen = 5000;
283
PC.RecPad = '.';
284
DbQueue file = (DbQueue)PC.Open(null, this.DBFilePath, null, DbType.Queue, Db.OpenFlags.Create|Db.OpenFlags.ThreadSafe, 0);
285
//CreateSecondaryDB(file,"Id.PCs.s",new DbFile.KeyGeneratorFcn(Common.Id));
286
//CreateSecondaryDB(file, "Id.PCs.s", new DbFile.KeyGeneratorFcn(Common.Id));
287
//由于数据量不是很大,不考虑使用二级数据库,直接使用游标操作,降低复杂度
288
//首先遍历数据库看有没有已经存在,如果没有,则添加一个,如果有,改变其状态
289
BinaryFormatter bf = new BinaryFormatter();
290
MemoryStream stream= new MemoryStream();
291
bf.Serialize(stream, value);
292
DbEntry k = DbEntry.Out(new byte[1024]);
293
DbEntry data = DbEntry.InOut(stream.ToArray());
294
file.Append(null, ref k, ref data);
295
stream.Close();
296
file.Sync();
297
PC.Close();
298
}
299
public int DeleteInQueueMode(Func<int, object, bool> predicate,bool isMatchOnlyOnce)
300
{
301
int count = 0;
302
if (predicate == null)
303
return 0;
304
//遍历数据
305
using (Db db = new Db(DbCreateFlags.None))
306
{
307
db.RecLen = 5000;
308
db.RecPad = '.';
309
//这里如果应用Db.OpenFlags.Create则在启动后会覆盖同名文件,并新建同名文件
310
//Db.OpenFlags.Truncate会清空数据库
311
DbQueue dbf = (DbQueue)db.Open(null, this.DBFilePath, null, DbType.Queue,
312
Db.OpenFlags.ThreadSafe|Db.OpenFlags.Create, 0);
313
314
using (DbQueueCursor cursor = dbf.OpenCursor(null, DbFileCursor.CreateFlags.None))
315
{
316
BinaryFormatter bf = new BinaryFormatter();
317
MemoryStream stream = new MemoryStream();
318
foreach (KeyDataPair kdp in cursor)
319
{
320
int k = BitConverter.ToInt32(kdp.Key.Buffer, 0);
321
Console.WriteLine("k={0}", k.ToString());
322
stream.SetLength(0);
323
stream.Position = 0;
324
stream.Write(kdp.Data.Buffer, 0, kdp.Data.Size);
325
stream.Seek(0, SeekOrigin.Begin);
326
object v = bf.Deserialize(stream);
327
if (predicate(k, v))
328
{
329
count++;
330
//string d = Encoding.UTF8.GetString(kdp.Data.Buffer, 0, kdp.Data.Size);
331
//如何读取Queue类型的主键值
332
333
334
//Console.WriteLine("{0},{1}", p2.State, p2.Os);
335
//p2.Os = "changed";
336
//stream = new MemoryStream();
337
//stream.Position = 0;
338
//stream.SetLength(0);
339
//bf.Serialize(stream, v);
340
//DbEntry data = DbEntry.InOut(stream.ToArray());
341
//cursor.Put(ref data);
342
cursor.Delete();
343
if (isMatchOnlyOnce)
344
{
345
stream.Close();
346
return count;
347
}
348
}
349
}stream.Close();
350
}
351
}
352
return count;
353
}
354
355
/// <summary>
356
/// 用于向支持重复键值的数据库文件添加数据
357
/// </summary>
358
/// <param name="key"></param>
359
/// <param name="value"></param>
360
public void CreateInHashModeWithDup(string key,object value)
361
{
362
//这里只是更新了一条记录,更新多条同key的情况没有考虑
363
Db db = new Db(DbCreateFlags.None);
364
db.SetFlags(DbFlags.Dup);
365
DbFile dbf = db.Open(null, this.DBFilePath, null, DbType.Hash, Db.OpenFlags.Create|Db.OpenFlags.ThreadSafe, 0);
366
MemoryStream stream = new MemoryStream();
367
BinaryFormatter formatter = new BinaryFormatter();
368
formatter.Serialize(stream, value);
369
DbEntry _key = DbEntry.InOut(Encoding.UTF8.GetBytes(key));
370
DbEntry _data = DbEntry.InOut(stream.ToArray());
371
if (dbf.Put(null, ref _key, ref _data) != 0)
372
Console.Write("{0}:输入错误", key);
373
stream.Close();
374
dbf.Sync();//数据更新
375
db.Close();
376
}
377
/// <summary>
378
/// 默认方式,如果已有键则进行更新操作
379
/// </summary>
380
/// <param name="key"></param>
381
/// <param name="value"></param>
382
public void CreateOrUpdateInHashModeWithoutDup(string key,object value)
383
{
384
//这里只是更新了一条记录,更新多条同key的情况没有考虑
385
Db db = new Db(DbCreateFlags.None);
386
//db.SetFlags(DbFlags.Dup);
387
DbFile dbf = db.Open(null, this.DBFilePath, null, DbType.Hash, Db.OpenFlags.Create|Db.OpenFlags.ThreadSafe, 0);
388
MemoryStream stream = new MemoryStream();
389
BinaryFormatter formatter = new BinaryFormatter();
390
formatter.Serialize(stream, value);
391
DbEntry _key = DbEntry.InOut(Encoding.UTF8.GetBytes(key));
392
DbEntry _data = DbEntry.InOut(stream.ToArray());
393
if (dbf.Put(null, ref _key, ref _data) != 0)
394
Console.Write("{0}:输入错误", key);
395
stream.Close();
396
dbf.Sync();//数据更新
397
db.Close();
398
}
399
public int UpdateInHashMode(Func<string,object,bool> predicate,object value,bool isMatchOnlyOnce)
400
{
401
int count = 0;
402
if (predicate == null)
403
return count;
404
//遍历数据
405
using (Db db = new Db(DbCreateFlags.None))
406
{
407
//这里如果应用Db.OpenFlags.Create则在启动后会覆盖同名文件,并新建同名文件
408
//Db.OpenFlags.Truncate会清空数据库
409
DbHash dbf = (DbHash)db.Open(null, this.DBFilePath, null, DbType.Hash,
410
Db.OpenFlags.ThreadSafe|Db.OpenFlags.Create, 0);
411
412
using (DbHashCursor cursor = dbf.OpenCursor(null, DbFileCursor.CreateFlags.None))
413
{
414
BinaryFormatter bf = new BinaryFormatter();
415
MemoryStream stream = new MemoryStream();
416
foreach (KeyDataPair kvp in cursor)
417
{
418
stream.SetLength(0);
419
stream.Position = 0;
420
stream.Write(kvp.Data.Buffer, 0, kvp.Data.Size);
421
stream.Seek(0, SeekOrigin.Begin);
422
string k = Encoding.UTF8.GetString(kvp.Key.Buffer, 0, kvp.Key.Size);
423
object v = bf.Deserialize(stream);
424
if (predicate(k, v))
425
{
426
count++;
427
stream.SetLength(0);
428
stream.Position = 0;
429
bf.Serialize(stream, value);
430
DbEntry data = DbEntry.InOut(stream.ToArray());
431
cursor.Put(ref data, DbKeyCursor<DbHashCursor, DbHash>.PutMode.Current);
432
if (isMatchOnlyOnce)
433
{
434
stream.Close();
435
return count;
436
}
437
}
438
}
439
stream.Close();
440
}
441
}
442
return count;
443
}
444
public int DeleteInHashMode(Func<string,object,bool> predicate,bool isMatchOnlyOnce)
445
{
446
int count = 0;
447
if (predicate == null)
448
return count;
449
//遍历数据
450
using (Db db = new Db(DbCreateFlags.None))
451
{
452
//这里如果应用Db.OpenFlags.Create则在启动后会覆盖同名文件,并新建同名文件
453
//Db.OpenFlags.Truncate会清空数据库
454
DbHash dbf = (DbHash)db.Open(null, this.DBFilePath, null, DbType.Hash,
455
Db.OpenFlags.ThreadSafe|Db.OpenFlags.Create, 0);
456
457
using (DbHashCursor cursor = dbf.OpenCursor(null, DbFileCursor.CreateFlags.None))
458
{
459
BinaryFormatter bf = new BinaryFormatter();
460
MemoryStream stream = new MemoryStream();
461
foreach (KeyDataPair kvp in cursor)
462
{
463
stream.SetLength(0);
464
stream.Position = 0;
465
stream.Write(kvp.Data.Buffer, 0, kvp.Data.Size);
466
stream.Seek(0, SeekOrigin.Begin);
467
string k = Encoding.UTF8.GetString(kvp.Key.Buffer, 0, kvp.Key.Size);
468
object v = bf.Deserialize(stream);
469
if (predicate(k, v))
470
{
471
count++;
472
cursor.Delete();
473
if (isMatchOnlyOnce)
474
{
475
stream.Close();
476
return count;
477
}
478
}
479
}
480
stream.Close();
481
}
482
}
483
return count;
484
}
485
}
486
}
487

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

85

86

87

88

121

122

123

124

125

126

127

128

129

130

131

132

150

151

152

153

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

408

409

410

411

412

413

414

415

416

417

418

419

420

421

422

423

424

425

426

427

428

429

430

431

432

433

434

435

436

437

438

439

440

441

442

443

444

445

446

447

448

449

450

451

452

453

454

455

456

457

458

459

460

461

462

463

464

465

466

467

468

469

470

471

472

473

474

475

476

477

478

479

480

481

482

483

484

485

486

487

unit test code
1
using
System;
2
using
System.Collections.Generic;
3
using
System.Linq;
4
using
System.Text;
5
using
Component;
6
using
MbUnit.Framework;
7
8
namespace
ToolManager.Test
9
{
10
[TestFixture]
11
class BDBHelperTest2
12
{
13
hash mode unit test
69
70
queue mode unit test
103
104
}
105
}
106

2

3

4

5

6

7

8

9

10

11

12

13

69

70

103

104

105

106

本文参考链接:https://www.cnblogs.com/lexus/archive/2008/08/24/1275164.html