码迷,mamicode.com
首页 > 移动开发 > 详细

小型文件数据库 (a file database for small apps) SharpFileDB

时间:2015-06-22 08:41:56      阅读:158      评论:0      收藏:0      [点我收藏+]

标签:

小型文件数据库 (a file database for small apps) SharpFileDB

For english version of this article, please click here.

我并不擅长数据库,如有不当之处,请多多指教。

本文参考了(http://www.cnblogs.com/gaochundong/archive/2013/04/24/csharp_file_database.html),在此表示感谢!

目标(Goal)

技术分享

我决定做一个以支持小型应用(万人级别)为目标的数据库。

既然是小型的数据库,那么最好不要依赖其它驱动、工具包,免得拖泥带水难以实施。

完全用C#编写成DLL,易学易用。

支持CRUD(增加(Create)、读取(Retrieve)、更新(Update)和删除(Delete))。

不使用SQL,客观原因我不擅长SQL,主观原因我不喜欢SQL,情景原因没有必要。

直接用文本文件或二进制文件存储数据。开发时用文本文件,便于调试;发布时用二进制文件,比较安全。

简单来说,就是纯C#、小型、无SQL。此类库就命名为SharpFileDB

为了便于共同开发,我把这个项目放到Github上,并且所有类库代码的注释都是中英文双语的。中文便于理解,英文便于今后国际化。也许我想的太多了。

设计草图(sketch)

使用场景(User Scene)

SharpFileDB库的典型使用场景如下。

 1                 // common cases to use SharpFileDB.
 2                 FileDBContext db = new FileDBContext();
 3 
 4                 Cat cat = new Cat();
 5                 cat.Name = "xiao xiao bai";
 6                 db.Create(cat);
 7 
 8                 Predicate<Cat> pre = new Predicate<Cat>(x => x.Name == "xiao xiao bai");
 9                 IList<Cat> cats = db.Retrieve(pre);
10 
11                 cat.Name = "xiao bai";
12                 db.Update(cat);
13 
14                 db.Delete(cat);

这个场景里包含了创建数据库和使用CRUD操作的情形。

我们就从这个使用场景开始设计出第一版最简单的一个文件数据库。

表vs类型(Table vs Type)

为方便叙述,下面我们以Cat为例进行说明。

 1     /// <summary>
 2     /// demo file object
 3     /// </summary>
 4     public class Cat : FileObject
 5     {
 6         public string Name { get; set; }
 7         public int Legs { get; set; }
 8 
 9         public override string ToString()
10         {
11             return string.Format("{0}, Name: {1}, Legs: {2}", base.ToString(), Name, Legs);
12         }
13     }

Cat这个类型就等价于关系数据库里的一个Table。

Cat的一个实例,就等价于关系数据库的Table里的一条记录。

以后我们把这样的类型称为表类型

全局唯一的主键(global unique main key)

类似关系数据库的主键,我们需要用全局唯一的Id来区分每个对象。每个表类型的实例都需要这样一个Id,那么我们就用一个abstract基类做这件事。

 1     /// <summary>
 2     /// 可在文件数据库中使用CRUD操作的所有类型的基类。
 3     /// Base class for all classed that can use CRUD in SharpFileDB.
 4     /// </summary>
 5     [Serializable]
 6     public abstract class FileObject
 7     {
 8         /// <summary>
 9         /// 主键.
10         /// main key.
11         /// </summary>
12         public Guid Id { get; set; }
13 
14         /// <summary>
15         /// 创建一个文件对象,并自动为其生成一个全局唯一的Id。
16         /// <para>Create a <see cref="FileObject"/> and generate a global unique id for it.</para>
17         /// </summary>
18         public FileObject()
19         {
20             this.Id = Guid.NewGuid();
21         }
22 
23         public override string ToString()
24         {
25             return string.Format("Id: {0}", this.Id);
26         }
27     }

 

数据库(FileDBContext)

一个数据库上下文负责各种类型的文件对象的CRUD操作。

技术分享
  1     /// <summary>
  2 /// 文件数据库。
  3     /// Represents a file database.
  4     /// </summary>
  5     public class FileDBContext
  6     {
  7         #region Fields
  8 
  9         /// <summary>
 10         /// 文件数据库操作锁
 11         /// <para>database operation lock.</para>
 12         /// </summary>
 13         protected static readonly object operationLock = new object();
 14 
 15         /// <summary>
 16         /// 文件数据库
 17         /// <para>Represents a file database.</para>
 18         /// </summary>
 19         /// <param name="directory">数据库文件所在目录<para>Directory for all files of database.</para></param>
 20         public FileDBContext(string directory = null)
 21         {
 22             if (directory == null)
 23             {
 24                 this.Directory = Environment.CurrentDirectory;
 25             }
 26             else
 27             {
 28                 Directory = directory;
 29             }
 30         }
 31 
 32         #endregion
 33 
 34         public override string ToString()
 35         {
 36             return string.Format("@: {0}", Directory);
 37         }
 38 
 39         #region Properties
 40 
 41         /// <summary>
 42         /// 数据库文件所在目录
 43         /// <para>Directory of database files.</para>
 44         /// </summary>
 45         public virtual string Directory { get; protected set; }
 46 
 47         #endregion
 48 
 49 
 50         protected string Serialize(FileObject item)
 51         {
 52             using (StringWriterWithEncoding sw = new StringWriterWithEncoding(Encoding.UTF8))
 53             {
 54                 XmlSerializer serializer = new XmlSerializer(item.GetType());
 55                 serializer.Serialize(sw, item);
 56                 string serializedString = sw.ToString();
 57 
 58                 return serializedString;
 59             }
 60         }
 61 
 62         /// <summary>
 63         /// 将字符串反序列化成文档对象
 64         /// </summary>
 65         /// <typeparam name="TDocument">文档类型</typeparam>
 66         /// <param name="serializedFileObject">字符串</param>
 67         /// <returns>
 68         /// 文档对象
 69         /// </returns>
 70         protected TFileObject Deserialize<TFileObject>(string serializedFileObject)
 71             where TFileObject : FileObject
 72         {
 73             if (string.IsNullOrEmpty(serializedFileObject))
 74                 throw new ArgumentNullException("data");
 75 
 76             using (StringReader sr = new StringReader(serializedFileObject))
 77             {
 78                 XmlSerializer serializer = new XmlSerializer(typeof(TFileObject));
 79                 object deserializedObj = serializer.Deserialize(sr);
 80                 TFileObject fileObject = deserializedObj as TFileObject;
 81                 return fileObject;
 82             }
 83         }
 84 
 85         protected string GenerateFileFullPath(FileObject item)
 86         {
 87             string path = GenerateFilePath(item.GetType());
 88             string name = item.GenerateFileName();
 89             string fullname = Path.Combine(path, name);
 90             return fullname;
 91         }
 92 
 93         /// <summary>
 94         /// 生成文件路径
 95         /// </summary>
 96         /// <typeparam name="TDocument">文档类型</typeparam>
 97         /// <returns>文件路径</returns>
 98         protected string GenerateFilePath(Type type)
 99         {
100             string path = Path.Combine(this.Directory, type.Name);
101             return path;
102         }
103 
104         #region CRUD
105 
106         /// <summary>
107         /// 增加一个<see cref="FileObject"/>到数据库。这实际上创建了一个文件。
108         /// <para>Create a new <see cref="FileObject"/> into database. This operation will create a new file.</para>
109         /// </summary>
110         /// <param name="item"></param>
111         public virtual void Create(FileObject item)
112         {
113             string fileName = GenerateFileFullPath(item);
114             string output = Serialize(item);
115 
116             lock (operationLock)
117             {
118                 System.IO.FileInfo info = new System.IO.FileInfo(fileName);
119                 System.IO.Directory.CreateDirectory(info.Directory.FullName);
120                 System.IO.File.WriteAllText(fileName, output);
121             }
122         }
123 
124         /// <summary>
125         /// 检索符合给定条件的所有<paramref name="TFileObject"/>126         /// <para>Retrives all <paramref name="TFileObject"/> that satisfies the specified condition.</para>
127         /// </summary>
128         /// <typeparam name="TFileObject"></typeparam>
129         /// <param name="predicate">检索出的对象应满足的条件。<para>THe condition that should be satisfied by retrived object.</para></param>
130         /// <returns></returns>
131         public virtual IList<TFileObject> Retrieve<TFileObject>(Predicate<TFileObject> predicate)
132             where TFileObject : FileObject
133         {
134             IList<TFileObject> result = new List<TFileObject>();
135             if (predicate != null)
136             {
137                 string path = GenerateFilePath(typeof(TFileObject));
138                 string[] files = System.IO.Directory.GetFiles(path, "*.xml", SearchOption.AllDirectories);
139                 foreach (var item in files)
140                 {
141                     string fileContent = File.ReadAllText(item);
142                     TFileObject deserializedFileObject = Deserialize<TFileObject>(fileContent);
143                     if (predicate(deserializedFileObject))
144                     {
145                         result.Add(deserializedFileObject);
146                     }
147                 }
148             }
149 
150             return result;
151         }
152 
153         /// <summary>
154         /// 更新给定的对象。
155         /// <para>Update specified <paramref name="FileObject"/>.</para>
156         /// </summary>
157         /// <param name="item">要被更新的对象。<para>The object to be updated.</para></param>
158         public virtual void Update(FileObject item)
159         {
160             string fileName = GenerateFileFullPath(item);
161             string output = Serialize(item);
162 
163             lock (operationLock)
164             {
165                 System.IO.FileInfo info = new System.IO.FileInfo(fileName);
166                 System.IO.Directory.CreateDirectory(info.Directory.FullName);
167                 System.IO.File.WriteAllText(fileName, output);
168             }
169         }
170 
171         /// <summary>
172         /// 删除指定的对象。
173         /// <para>Delete specified <paramref name="FileObject"/>.</para>
174         /// </summary>
175         /// <param name="item">要被删除的对象。<para>The object to be deleted.</para></param>
176         public virtual void Delete(FileObject item)
177         {
178             if (item == null)
179             {
180                 throw new ArgumentNullException(item.ToString());
181             }
182 
183             string filename = GenerateFileFullPath(item);
184             if (File.Exists(filename))
185             {
186                 lock (operationLock)
187                 {
188                     File.Delete(filename);
189                 }
190             }
191         }
192 
193         #endregion CRUD
194 
195     }
FileDBContext

 

文件存储方式(Way to store files)

在数据库目录下,SharpFileDB为每个表类型创建一个文件夹,在各自文件夹内存储每个对象。每个对象都占用一个XML文件。暂时用XML格式,因为是.NET内置的格式,省的再找外部序列化工具。XML文件名与其对应的对象Id相同。

技术分享

 

 

下载(Download)

我已将源码放到(https://github.com/bitzhuwei/SharpFileDB/),欢迎试用、提建议或Fork此项目。

 

PS:我国大多数县的人口为几万到几十万。目前,县里各种政府部门急需实现信息化网络化办公办事,但他们一般用不起那种月薪上万的开发者和高端软件公司。我注意到,一个县级政府部门日常应对的人群数量就是万人左右,甚至常常是千人左右。所以他们不需要太高端复杂的系统设计,用支持万人级别的数据库就可以了。另一方面,初级开发者也不能充分利用那些看似高端复杂的数据库的优势。做个小型系统而已,还是简单一点好。

所以我就想做这样一个小型文件数据库,我相信这会帮助很多人。能以己所学惠及大众,才是我们的价值所在。

小型文件数据库 (a file database for small apps) SharpFileDB

标签:

原文地址:http://www.cnblogs.com/bitzhuwei/p/SharpFileDB.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!