转载请注明出处 http://www.cnblogs.com/68681395
1
//是否写日志
2
#define txtLogAll
3
4
using System;
5
using System.Web;
6
using System.Xml.Serialization;
7
using System.IO;
8
using System.Runtime.Serialization;
9
using System.Runtime.Serialization.Formatters.Soap;
10
using System.Runtime.Serialization.Formatters.Binary;
11
using System.Web.Caching;
12
using System.Threading;
13
using tjb.Utility.Caching;
14
using System.Xml;
15
using System.Text;
16
17
18
namespace tjb.Utility.Config
19

{
20
21
文件序列化的类型#region 文件序列化的类型
22
/**//// <summary>
23
/// 序列化文件的方式
24
/// Binary,Xml,SoapXml
25
/// </summary>
26
public enum Formatter
27
{
28
/**//// <summary>
29
/// 字节
30
/// </summary>
31
Binary,
32
/**//// <summary>
33
/// xml
34
/// </summary>
35
Xml,
36
/**//// <summary>
37
/// soap协议的xml
38
/// </summary>
39
SoapXml
40
}
41
#endregion
42
43
/**//// <summary>
44
/// 序列化基类 by Tjb 2007/06
45
/// T 类型不能创建多态的多个实例
46
/// 优化和修正,增加配置文件备份 2008/9/18
47
/// 修改:获取实例时加锁
48
/// 修改:
49
/// SaveAs(T Tobj, string FileFullName, bool BackupOnError) 方法增加线程锁定。防止多线程冲突 2008/10/24
50
/// </summary>
51
/// <typeparam name="T">T 必须有无参数的构造函数</typeparam>
52
[Serializable]
53
public abstract class IConfig<T> where T : IConfig<T>, new()
54
{
55
56
Exceptions#region Exceptions
57
private Exception __ConfigException;
58
/**//// <summary>
59
/// 读取或保存时发生的错误
60
/// </summary>
61
[XmlIgnore, SoapIgnore]
62
public Exception Exception
63
{
64
get
65
{
66
return __ConfigException;
67
}
68
private set
69
{
70
if (value != null)
71
{
72
HasError = true;
73
__ConfigException = value;
74
#if txtLogAll
75
Log.WriteLog(value);
76
#endif
77
}
78
}
79
}
80
private bool __HasError = false;
81
/**//// <summary>
82
/// 获取一个值 指示读取或者保存时是否发生错误
83
/// 如果当前错误被获取后,此标志将被置为false
84
/// </summary>
85
[XmlIgnore, SoapIgnore]
86
public bool HasError
87
{
88
get
{ return __HasError; }
89
private set
{ __HasError = value; }
90
}
91
#endregion
92
93
序列化类型 可重写#region 序列化类型 可重写
94
95
private Formatter _CurrentFormatter = Formatter.Xml;
96
/**//// <summary>
97
/// 序列化的方式
98
/// </summary>
99
[XmlIgnore]
100
protected virtual Formatter CurrentFormatter
101
{
102
get
103
{
104
return _CurrentFormatter;
105
}
106
set
107
{
108
_CurrentFormatter = value;
109
}
110
}
111
112
#endregion
113
114
获取单个实例#region 获取单个实例
115
116
/**//// <summary>
117
/// 获取Cache中缓存T的key
118
/// </summary>
119
public static string CacheKEY
120
{
121
get
122
{
123
// return typeof(T).GUID.ToString("N");
124
return typeof(T).FullName;
125
}
126
}
127
/**//// <summary>
128
/// 从缓存(缓存KEY为T的命空间加类名)获取当前类的实例,如果缓存不存在则读取文件(ConfigFileFullName), 并缓存。
129
/// </summary>
130
public static T Instance
131
{
132
get
133
{
134
T c = CacheUtility.Get<T>(CacheKEY);
135
if (c == null)
136
{
137
//这中方式无异于不加锁
138
//object Monitor = new object();
139
//lock (Monitor)
140
lock (typeof(T))
141
{
142
c = CacheUtility.Get<T>(CacheKEY);
143
if (c == null)
144
{
145
c = new T().Read();
146
#if DEBUG
147
CacheUtility.SetSlidingExpiration(CacheKEY, c, c.ConfigFileFullName, 7, CacheItemPriority.NotRemovable, new CacheItemRemovedCallback(CallR));
148
#else
149
CacheUtility.SetSlidingExpiration(CacheKEY, c, c.ConfigFileFullName, 7, CacheItemPriority.NotRemovable, null);
150
#endif
151
}
152
}
153
}
154
return c;
155
}
156
}
157
158
#endregion
159
160
Caching..#region Caching..
161
162
/**//// <summary>
163
/// 从ConfigFileName指定文件以CurrentSerializeType读取实例,如果存在缓存则移除并重新进行缓存
164
/// 如果不存在则以InitConfig初始化类,创建并保存文件
165
/// </summary>
166
/// <returns></returns>
167
protected T ResetCacheAndRead()
168
{
169
ResetCache();
170
return Read();
171
}
172
/**//// <summary>
173
/// 移除CacheKEY 缓存
174
/// </summary>
175
public void ResetCache()
176
{
177
HttpRuntime.Cache.Remove(CacheKEY);
178
}
179
#endregion
180
181
获取#region 获取
182
183
/**//// <summary>
184
/// 读取缓存中的实例如果不存在则
185
/// 从ConfigFileName指定文件以CurrentSerializeType读取实例
186
/// 如果不存在则以InitConfig初始化类,创建并保存文件
187
/// </summary>
188
/// <returns></returns>
189
virtual protected T Read()
190
{
191
return Read(ConfigFileFullName, true, CurrentFormatter);
192
}
193
194
/**//// <summary>
195
/// 从ConfigFileName指定文件以CurrentSerializeType读取实例
196
/// 如果不存在则以InitConfig初始化类,创建并保存文件
197
/// </summary>
198
/// <param name="configFileFullName">缓存文件绝对路径</param>
199
/// <param name="serializeType"></param>
200
/// <param name="BackupOnError">读取错误时是否备份</param>
201
/// <returns></returns>
202
protected T Read(string configFileFullName, bool BackupOnError, Formatter serializeType)
203
{
204
T t = CacheUtility.Get<T>(CacheKEY);
205
if (t != null)
206
return t;
207
FileInfo fi = new FileInfo(configFileFullName);
208
if (fi.Exists)
209
{
210
211
FileStream fs = null;
212
try
213
{
214
open the stream
#region open the stream
215
// open the stream
216
fs = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
217
IFormatter formatter = null;
218
switch (serializeType)
219
{
220
case Formatter.Binary:
221
formatter = new BinaryFormatter();
222
t = formatter.Deserialize(fs) as T;
223
break;
224
case Formatter.SoapXml:
225
formatter = new SoapFormatter();
226
t = formatter.Deserialize(fs) as T;
227
break;
228
case Formatter.Xml:
229
XmlSerializer serializer = new XmlSerializer(typeof(T));
230
t = serializer.Deserialize(fs) as T;
231
break;
232
default:
233
break;
234
}
235
#endregion
236
237
if (fs != null)
238
fs.Close();
239
}
240
catch (Exception ex)
241
{
242
if (fs != null)
243
fs.Close();
244
t = CustomizingInit();
245
246
读取失败 进行备份 防止以后使用默认配置覆盖当前数据#region 读取失败 进行备份 防止以后使用默认配置覆盖当前数据
247
if (BackupOnError)
248
if (fi.Exists)
249
{
250
string BackupFilePath = fi.FullName + ".Read." + DateTime.Now.ToString("yyMMddHHssfff") + ".bak";
251
try
252
{
253
fi.CopyTo(BackupFilePath, true);
254
t.Save(true);
255
}
256
catch (Exception ioex)
257
{
258
t.Exception = new Exception("读取配置文件出错后,对配置文件进行备份发生错误!", ioex);
259
}
260
}
261
#endregion
262
263
t.Exception = new Exception("读取配置文件时发生错误!将返回CustomizingInit()方法的实例,默认为 new T()!", ex);
264
}
265
finally
266
{
267
268
}
269
}
270
else
271
{
272
t = CustomizingInit();
273
274
//不存在的同一文件不能读多次
275
//防止在CustomizingInit()方法中调用Read(string configFileName, SerializeType serializeType) 造成死循环
276
string ProtectedKEY = Thread.CurrentThread.ManagedThreadId + fi.FullName + "init";
277
if (CacheUtility.GetAnyType<bool>(ProtectedKEY) == false)
278
{
279
CacheUtility.SetAbsoluteExpiration(ProtectedKEY, true, null, 0.02);
280
}
281
else
282
{
283
CacheUtility.Remove(ProtectedKEY);
284
throw new Exception("'" + fi.FullName + "' 文件不存在!读取过于频繁。导致此保护异常发生。");
285
}
286
t.Exception = new Exception("配置文件:'" + fi.FullName + "' 不存在!默认返回CustomizingInit()方法返回的实例。");
287
}
288
if (t == null)
289
t.Exception = new Exception("发生错误,请检查初始化配置方法 CustomizingInit() 未返回的配置实例不能为空,或者系统中存在缓存 key :" + CacheKEY);
290
return t;
291
}
292
293
#if DEBUG
294
private static void CallR(string key, object obj, CacheItemRemovedReason re)
295
{
296
#if txtLogAll
297
Log.WriteLog(key + "::::" + re.ToString());
298
#endif
299
}
300
#endif
301
302
#endregion
303
304
保存#region 保存
305
/**//// <summary>
306
/// 将当前实例进行保存
307
/// </summary>
308
/// <param name="BackupOnError">发生错误时是否备份</param>
309
/// <returns></returns>
310
public bool Save(bool BackupOnError)
311
{
312
if (Current == null)
313
{
314
Exception = new Exception(typeof(T).FullName + " 未正确实现 Current;");
315
return false;
316
}
317
return Save(Current, BackupOnError);
318
}
319
/**//// <summary>
320
/// 将当前实例进行保存
321
/// 发生错误时将备份配置文件
322
/// </summary>
323
/// <returns></returns>
324
public virtual bool Save()
325
{
326
return Save(true);
327
}
328
329
/**//// <summary>
330
/// 将当前实例保存到T.ConfigFileName指定的配置文件
331
/// </summary>
332
/// <param name="Tobj"></param>
333
/// <param name="BackupOnError"></param>
334
/// <returns></returns>
335
public bool Save(T Tobj, bool BackupOnError)
336
{
337
return SaveAs(Tobj, ConfigFileFullName, BackupOnError);
338
}
339
340
/**//// <summary>
341
/// 将一个实例对象保存到FileFullName指定的配置文件
342
/// </summary>
343
/// <param name="FileFullName"></param>
344
/// <param name="Tobj"></param>
345
/// <param name="BackupOnError"></param>
346
/// <returns></returns>
347
protected bool SaveAs(T Tobj, string FileFullName, bool BackupOnError)
348
{
349
lock (typeof(T))
350
{
351
if (Tobj == default(T))
352
{
353
Exception = new Exception(typeof(T).FullName + " 未正确实现 Current;");
354
return false;
355
}
356
FileStream fs = null;
357
FileInfo fi = new FileInfo(FileFullName);
358
string BackupFilePath = null;
359
360
if (BackupOnError)
361
{
362
backup#region backup
363
364
BackupFilePath = fi.FullName + ".Save." + DateTime.Now.ToString("yyMMddHHssfff") + ".bak";
365
try
366
{
367
//如果存在先备份
368
if (fi.Exists)
369
{
370
fi.CopyTo(BackupFilePath, true);
371
}
372
else if (!fi.Directory.Exists)
373
{
374
//目录不存在创建目录
375
fi.Directory.Create();
376
}
377
}
378
catch (Exception ex)
379
{
380
Tobj.Exception = new Exception("备份配置文件时发生错误!", ex);
381
return false;
382
}
383
#endregion
384
}
385
386
try
387
{
388
if (fi.Exists)
389
fi.Delete();
390
serialize it
#region serialize it
391
fs = new FileStream(fi.FullName, FileMode.Create, FileAccess.Write, FileShare.Read);
392
IFormatter formatter = null;
393
switch (CurrentFormatter)
394
{
395
case Formatter.Binary:
396
formatter = new BinaryFormatter();
397
formatter.Serialize(fs, Tobj);
398
break;
399
case Formatter.SoapXml:
400
formatter = new SoapFormatter();
401
formatter.Serialize(fs, Tobj);
402
break;
403
case Formatter.Xml:
404
XmlSerializer serializer = new XmlSerializer(typeof(T));
405
406
serializer.Serialize(fs, Tobj);
407
break;
408
default:
409
break;
410
}
411
#endregion
412
413
//成功则删除当前备份
414
415
成功则删除当前备份#region 成功则删除当前备份
416
if (BackupOnError)
417
try
418
{
419
File.Delete(BackupFilePath);
420
}
421
catch (Exception ex)
422
{
423
Tobj.Exception = new Exception("删除备份文件时发生错误!", ex);
424
}
425
#endregion
426
427
return true;
428
}
429
catch (Exception ex)
430
{
431
#if txtLog
432
Log.WriteLog(ex);
433
#endif
434
Tobj.Exception = new Exception("保存配置文件时发生错误!", ex);
435
436
return false;
437
}
438
finally
439
{
440
if (fs != null)
441
fs.Close();
442
}
443
}
444
}
445
#endregion
446
447
删除配置文件#region 删除配置文件
448
/**//// <summary>
449
/// 删除配置文件
450
/// </summary>
451
/// <returns></returns>
452
public bool Delete()
453
{
454
return Delete(ConfigFileFullName);
455
}
456
/**//// <summary>
457
/// 删除指定的配置文件 .文件不存在不引发异常。并返回true
458
/// </summary>
459
/// <param name="FileFullName"></param>
460
/// <returns></returns>
461
public bool Delete(string FileFullName)
462
{
463
try
464
{
465
if (File.Exists(FileFullName))
466
File.Delete(FileFullName);
467
return true;
468
}
469
catch (Exception ex)
470
{
471
Current.Exception = ex;
472
return false;
473
}
474
}
475
#endregion
476
477
抽象成员#region 抽象成员
478
/**//// <summary>
479
/// 返回派生类的当前实例
480
/// protected override T Current
481
/// {
482
/// get
483
/// {
484
/// return this;
485
/// }
486
/// }
487
/// </summary>
488
protected abstract T Current
489
{
490
get;
491
}
492
/**//// <summary>
493
/// 自定义初始化配置类
494
/// 获取 T 的配置实例时,如果配置文件不存在或者读取失败时返回此实例
495
/// 重写中一般读取备份的配置文件,必须保证备份配置文件存在,否则发生异常。
496
/// 默认返回 new T();
497
/// </summary>
498
/// <returns></returns>
499
protected virtual T CustomizingInit()
500
{
501
return Current;
502
}
503
/**//// <summary>
504
/// 配置文件名
505
/// <c>配置文件名</c>
506
/// <example>
507
/// 配置文件名
508
/// </example>
509
/// </summary>
510
private string ___file = Path.Combine(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "Config/" + typeof(T).Name + ".cfg");
511
/**//// <summary>
512
/// 配置文件全路径名
513
/// 默认:winform 在应用程序目录;web应用程序默认bin目录。
514
/// </summary>
515
[XmlIgnore]
516
public virtual string ConfigFileFullName
517
{
518
get
519
{
520
return ___file;
521
}
522
set
523
{
524
___file = value;
525
}
526
}
527
#endregion
528
}
529
}
530

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



55

56


57

58


59

60

61

62

63



64

65



66

67

68

69



70

71



72

73

74

75

76

77

78

79

80

81


82

83

84

85

86

87



88



89



90

91

92

93


94

95

96


97

98

99

100

101



102

103



104

105

106

107



108

109

110

111

112

113

114


115

116


117

118

119

120



121

122



123

124

125

126

127


128

129

130

131



132

133



134

135

136



137

138

139

140

141



142

143

144



145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160


161

162


163

164

165

166

167

168



169

170

171

172


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

488

489



490

491

492


493

494

495

496

497

498

499

500



501

502

503


504

505

506

507

508

509

510

511


512

513

514

515

516

517



518

519



520

521

522

523



524

525

526

527

528

529

530
