zoukankan      html  css  js  c++  java
  • C#实现文件数据库

    本文转载:http://www.cnblogs.com/gaochundong/archive/2013/04/24/csharp_file_database.html#commentform

    本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载。

    如果你需要一个简单的磁盘文件索引数据库,这篇文章可以帮助你。

    文件数据库描述:

    • 每个文档对象保存为一个独立文件,例如一篇博客。
    • 文件内容序列化支持XML或JSON。
    • 支持基本的CRUD操作。

    文件数据库抽象类实现

    View Code
      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>() { '', ' ', '.', '$', '/', '\' };
     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   }

    XML文件数据库实现

    复制代码
     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   }
    复制代码

    JSON文件数据库实现

    复制代码
     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   }
    复制代码

    Test Double

    复制代码
     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:	mp");
    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:	mp");
    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   }
    复制代码

     

  • 相关阅读:
    数据结构之整数划分问题(转)
    各种排序方法的收集
    bloom filter 的Java 版
    常见面试题学习(3)
    优先级队列的Java ,C++ STL,堆实现
    常见面试题学习(2)
    常见面试题学习(5)
    常见面试题学习(4)
    常见面试题学习(1)
    bitmap与桶方式对1000万数据进行排序(转+自己实现理解)
  • 原文地址:https://www.cnblogs.com/51net/p/3620171.html
Copyright © 2011-2022 走看看