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

     

  • 相关阅读:
    广域网(ppp协议、HDLC协议)
    0120. Triangle (M)
    0589. N-ary Tree Preorder Traversal (E)
    0377. Combination Sum IV (M)
    1074. Number of Submatrices That Sum to Target (H)
    1209. Remove All Adjacent Duplicates in String II (M)
    0509. Fibonacci Number (E)
    0086. Partition List (M)
    0667. Beautiful Arrangement II (M)
    1302. Deepest Leaves Sum (M)
  • 原文地址:https://www.cnblogs.com/51net/p/3620171.html
Copyright © 2011-2022 走看看