本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载。
如果你需要一个简单的磁盘文件索引数据库,这篇文章可以帮助你。
文件数据库描述:
1 /// <summary>
2 /// 文件数据库,这是一个抽象类。
3 /// </summary>
4 public abstract class FileDatabase
5 {
6 #region Fields
7
8 /// <summary>
9 /// 文件数据库操作锁
10 /// </summary>
11 protected static readonly object operationLock = new object();
12 private static HashSet<char> invalidFileNameChars;
13
14 static FileDatabase()
15 {
16 invalidFileNameChars = new HashSet<char>() { '\0', ' ', '.', '$', '/', '\\' };
17 foreach (var c in Path.GetInvalidPathChars()) { invalidFileNameChars.Add(c); }
18 foreach (var c in Path.GetInvalidFileNameChars()) { invalidFileNameChars.Add(c); }
19 }
20
21 /// <summary>
22 /// 文件数据库
23 /// </summary>
24 /// <param name="directory">数据库文件所在目录</param>
25 protected FileDatabase(string directory)
26 {
27 Directory = directory;
28 }
29
30 #endregion
31
32 #region Properties
33
34 /// <summary>
35 /// 数据库文件所在目录
36 /// </summary>
37 public virtual string Directory { get; private set; }
38
39 /// <summary>
40 /// 是否输出缩进
41 /// </summary>
42 public virtual bool OutputIndent { get; set; }
43
44 /// <summary>
45 /// 文件扩展名
46 /// </summary>
47 public virtual string FileExtension { get; set; }
48
49 #endregion
50
51 #region Public Methods
52
53 /// <summary>
54 /// 保存文档
55 /// </summary>
56 /// <typeparam name="TDocument">文档类型</typeparam>
57 /// <param name="document">文档对象</param>
58 /// <returns>文档ID</returns>
59 public virtual string Save<TDocument>(TDocument document)
60 {
61 return Save<TDocument>(ObjectId.NewObjectId().ToString(), document);
62 }
63
64 /// <summary>
65 /// 保存文档
66 /// </summary>
67 /// <typeparam name="TDocument">文档类型</typeparam>
68 /// <param name="id">文档ID</param>
69 /// <param name="document">文档对象</param>
70 /// <returns>文档ID</returns>
71 public virtual string Save<TDocument>(string id, TDocument document)
72 {
73 if (string.IsNullOrEmpty(id))
74 throw new ArgumentNullException("id");
75
76 if (document == null)
77 throw new ArgumentNullException("document");
78
79 Delete<TDocument>(id);
80
81 try
82 {
83 string fileName = GenerateFileFullPath<TDocument>(id);
84 string output = Serialize(document);
85
86 lock (operationLock)
87 {
88 System.IO.FileInfo info = new System.IO.FileInfo(fileName);
89 System.IO.Directory.CreateDirectory(info.Directory.FullName);
90 System.IO.File.WriteAllText(fileName, output);
91 }
92 }
93 catch (Exception ex)
94 {
95 throw new FileDatabaseException(
96 string.Format(CultureInfo.InvariantCulture,
97 "Save document failed with id [{0}].", id), ex);
98 }
99
100 return id;
101 }
102
103 /// <summary>
104 /// 根据文档ID查找文档
105 /// </summary>
106 /// <typeparam name="TDocument">文档类型</typeparam>
107 /// <param name="id">文档ID</param>
108 /// <returns>文档对象</returns>
109 public virtual TDocument FindOneById<TDocument>(string id)
110 {
111 if (string.IsNullOrEmpty(id))
112 throw new ArgumentNullException("id");
113
114 try
115 {
116 string fileName = GenerateFileFullPath<TDocument>(id);
117 if (File.Exists(fileName))
118 {
119 string fileData = File.ReadAllText(fileName);
120 return Deserialize<TDocument>(fileData);
121 }
122
123 return default(TDocument);
124 }
125 catch (Exception ex)
126 {
127 throw new FileDatabaseException(
128 string.Format(CultureInfo.InvariantCulture,
129 "Find document by id [{0}] failed.", id), ex);
130 }
131 }
132
133 /// <summary>
134 /// 查找指定类型的所有文档
135 /// </summary>
136 /// <typeparam name="TDocument">文档类型</typeparam>
137 /// <returns>文档对象序列</returns>
138 public virtual IEnumerable<TDocument> FindAll<TDocument>()
139 {
140 try
141 {
142 string[] files = System.IO.Directory.GetFiles(
143 GenerateFilePath<TDocument>(),
144 "*." + FileExtension,
145 SearchOption.TopDirectoryOnly);
146
147 List<TDocument> list = new List<TDocument>();
148 foreach (string fileName in files)
149 {
150 string fileData = File.ReadAllText(fileName);
151 TDocument document = Deserialize<TDocument>(fileData);
152 if (document != null)
153 {
154 list.Add(document);
155 }
156 }
157
158 return list;
159 }
160 catch (Exception ex)
161 {
162 throw new FileDatabaseException(
163 "Find all documents failed.", ex);
164 }
165 }
166
167 /// <summary>
168 /// 根据指定文档ID删除文档
169 /// </summary>
170 /// <typeparam name="TDocument">文档类型</typeparam>
171 /// <param name="id">文档ID</param>
172 public virtual void Delete<TDocument>(string id)
173 {
174 if (string.IsNullOrEmpty(id))
175 throw new ArgumentNullException("id");
176
177 try
178 {
179 string fileName = GenerateFileFullPath<TDocument>(id);
180 if (File.Exists(fileName))
181 {
182 lock (operationLock)
183 {
184 File.Delete(fileName);
185 }
186 }
187 }
188 catch (Exception ex)
189 {
190 throw new FileDatabaseException(
191 string.Format(CultureInfo.InvariantCulture,
192 "Delete document by id [{0}] failed.", id), ex);
193 }
194 }
195
196 /// <summary>
197 /// 删除所有指定类型的文档
198 /// </summary>
199 /// <typeparam name="TDocument">文档类型</typeparam>
200 public virtual void DeleteAll<TDocument>()
201 {
202 try
203 {
204 string[] files = System.IO.Directory.GetFiles(
205 GenerateFilePath<TDocument>(), "*." + FileExtension,
206 SearchOption.TopDirectoryOnly);
207
208 foreach (string fileName in files)
209 {
210 lock (operationLock)
211 {
212 File.Delete(fileName);
213 }
214 }
215 }
216 catch (Exception ex)
217 {
218 throw new FileDatabaseException(
219 "Delete all documents failed.", ex);
220 }
221 }
222
223 /// <summary>
224 /// 获取指定类型文档的数量
225 /// </summary>
226 /// <typeparam name="TDocument">文档类型</typeparam>
227 /// <returns>文档的数量</returns>
228 public virtual int Count<TDocument>()
229 {
230 try
231 {
232 string[] files = System.IO.Directory.GetFiles(
233 GenerateFilePath<TDocument>(),
234 "*." + FileExtension, SearchOption.TopDirectoryOnly);
235 if (files != null)
236 {
237 return files.Length;
238 }
239 else
240 {
241 return 0;
242 }
243 }
244 catch (Exception ex)
245 {
246 throw new FileDatabaseException(
247 "Count all documents failed.", ex);
248 }
249 }
250
251 #endregion
252
253 #region Protected Methods
254
255 /// <summary>
256 /// 生成文件全路径
257 /// </summary>
258 /// <typeparam name="TDocument">文档类型</typeparam>
259 /// <param name="id">文档ID</param>
260 /// <returns>文件路径</returns>
261 protected virtual string GenerateFileFullPath<TDocument>(string id)
262 {
263 return Path.Combine(GenerateFilePath<TDocument>(),
264 GenerateFileName<TDocument>(id));
265 }
266
267 /// <summary>
268 /// 生成文件路径
269 /// </summary>
270 /// <typeparam name="TDocument">文档类型</typeparam>
271 /// <returns>文件路径</returns>
272 protected virtual string GenerateFilePath<TDocument>()
273 {
274 return Path.Combine(this.Directory, typeof(TDocument).Name);
275 }
276
277 /// <summary>
278 /// 生成文件名
279 /// </summary>
280 /// <typeparam name="TDocument">文档类型</typeparam>
281 /// <param name="id">文档ID</param>
282 /// <returns>文件名</returns>
283 protected virtual string GenerateFileName<TDocument>(string id)
284 {
285 if (string.IsNullOrEmpty(id))
286 throw new ArgumentNullException("id");
287
288 foreach (char c in id)
289 {
290 if (invalidFileNameChars.Contains(c))
291 {
292 throw new FileDatabaseException(
293 string.Format(CultureInfo.InvariantCulture,
294 "The character '{0}' is not a valid file name identifier.", c));
295 }
296 }
297
298 return string.Format(CultureInfo.InvariantCulture, "{0}.{1}", id, FileExtension);
299 }
300
301 /// <summary>
302 /// 将指定的文档对象序列化至字符串
303 /// </summary>
304 /// <param name="value">指定的文档对象</param>
305 /// <returns>文档对象序列化后的字符串</returns>
306 protected abstract string Serialize(object value);
307
308 /// <summary>
309 /// 将字符串反序列化成文档对象
310 /// </summary>
311 /// <typeparam name="TDocument">文档类型</typeparam>
312 /// <param name="data">字符串</param>
313 /// <returns>文档对象</returns>
314 protected abstract TDocument Deserialize<TDocument>(string data);
315
316 #endregion
317 }
1 /// <summary>
2 /// XML文件数据库
3 /// </summary>
4 public class XmlDatabase : FileDatabase
5 {
6 /// <summary>
7 /// XML文件数据库
8 /// </summary>
9 /// <param name="directory">数据库文件所在目录</param>
10 public XmlDatabase(string directory)
11 : base(directory)
12 {
13 FileExtension = @"xml";
14 }
15
16 /// <summary>
17 /// 将指定的文档对象序列化至字符串
18 /// </summary>
19 /// <param name="value">指定的文档对象</param>
20 /// <returns>
21 /// 文档对象序列化后的字符串
22 /// </returns>
23 protected override string Serialize(object value)
24 {
25 if (value == null)
26 throw new ArgumentNullException("value");
27
28 using (StringWriterWithEncoding sw = new StringWriterWithEncoding(Encoding.UTF8))
29 {
30 XmlSerializer serializer = new XmlSerializer(value.GetType());
31 serializer.Serialize(sw, value);
32 return sw.ToString();
33 }
34 }
35
36 /// <summary>
37 /// 将字符串反序列化成文档对象
38 /// </summary>
39 /// <typeparam name="TDocument">文档类型</typeparam>
40 /// <param name="data">字符串</param>
41 /// <returns>
42 /// 文档对象
43 /// </returns>
44 protected override TDocument Deserialize<TDocument>(string data)
45 {
46 if (string.IsNullOrEmpty(data))
47 throw new ArgumentNullException("data");
48
49 using (StringReader sr = new StringReader(data))
50 {
51 XmlSerializer serializer = new XmlSerializer(typeof(TDocument));
52 return (TDocument)serializer.Deserialize(sr);
53 }
54 }
55 }
1 /// <summary>
2 /// JSON文件数据库
3 /// </summary>
4 public class JsonDatabase : FileDatabase
5 {
6 /// <summary>
7 /// JSON文件数据库
8 /// </summary>
9 /// <param name="directory">数据库文件所在目录</param>
10 public JsonDatabase(string directory)
11 : base(directory)
12 {
13 FileExtension = @"json";
14 }
15
16 /// <summary>
17 /// 将指定的文档对象序列化至字符串
18 /// </summary>
19 /// <param name="value">指定的文档对象</param>
20 /// <returns>
21 /// 文档对象序列化后的字符串
22 /// </returns>
23 protected override string Serialize(object value)
24 {
25 if (value == null)
26 throw new ArgumentNullException("value");
27
28 return JsonConvert.SerializeObject(value, OutputIndent);
29 }
30
31 /// <summary>
32 /// 将字符串反序列化成文档对象
33 /// </summary>
34 /// <typeparam name="TDocument">文档类型</typeparam>
35 /// <param name="data">字符串</param>
36 /// <returns>
37 /// 文档对象
38 /// </returns>
39 protected override TDocument Deserialize<TDocument>(string data)
40 {
41 if (string.IsNullOrEmpty(data))
42 throw new ArgumentNullException("data");
43
44 return JsonConvert.DeserializeObject<TDocument>(data);
45 }
46 }
1 [Serializable]
2 public class Cat
3 {
4 public Cat()
5 {
6 Id = ObjectId.NewObjectId().ToString();
7 }
8
9 public Cat(string id)
10 {
11 Id = id;
12 }
13
14 public string Name { get; set; }
15 public int Legs { get; set; }
16
17 public string Id { get; set; }
18
19 public override string ToString()
20 {
21 return string.Format("DocumentId={0}, Name={1}, Legs={2}", Id, Name, Legs);
22 }
23 }
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 TestJsonDatabase();
6 TestXmlDatabase();
7
8 Console.ReadKey();
9 }
10
11 private static void TestJsonDatabase()
12 {
13 JsonDatabase db = new JsonDatabase(@"C:\tmp");
14 db.OutputIndent = true;
15
16 Cat origin = new Cat() { Name = "Garfield", Legs = 4 };
17 db.Save<Cat>(origin);
18
19 db.Save<Cat>(origin.Id, origin);
20 db.Delete<Cat>(origin.Id);
21 }
22
23 private static void TestXmlDatabase()
24 {
25 XmlDatabase db = new XmlDatabase(@"C:\tmp");
26 db.OutputIndent = true;
27
28 Cat origin = new Cat() { Name = "Garfield", Legs = 4 };
29 db.Save<Cat>(origin);
30
31 db.Save<Cat>(origin.Id, origin);
32 db.Delete<Cat>(origin.Id);
33 }
34 }
本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载。