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

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

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

文件数据库描述:

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

文件数据库抽象类实现

   /// <summary>
/// 文件数据库,这是一个抽象类。
/// </summary>
public abstract class FileDatabase
{
#region Fields /// <summary>
/// 文件数据库操作锁
/// </summary>
protected static readonly object operationLock = new object();
private static HashSet<char> invalidFileNameChars; static FileDatabase()
{
invalidFileNameChars = new HashSet<char>() { '\0', ' ', '.', '$', '/', '\\' };
foreach (var c in Path.GetInvalidPathChars()) { invalidFileNameChars.Add(c); }
foreach (var c in Path.GetInvalidFileNameChars()) { invalidFileNameChars.Add(c); }
} /// <summary>
/// 文件数据库
/// </summary>
/// <param name="directory">数据库文件所在目录</param>
protected FileDatabase(string directory)
{
Directory = directory;
} #endregion #region Properties /// <summary>
/// 数据库文件所在目录
/// </summary>
public virtual string Directory { get; private set; } /// <summary>
/// 是否输出缩进
/// </summary>
public virtual bool OutputIndent { get; set; } /// <summary>
/// 文件扩展名
/// </summary>
public virtual string FileExtension { get; set; } #endregion #region Public Methods /// <summary>
/// 保存文档
/// </summary>
/// <typeparam name="TDocument">文档类型</typeparam>
/// <param name="document">文档对象</param>
/// <returns>文档ID</returns>
public virtual string Save<TDocument>(TDocument document)
{
return Save<TDocument>(ObjectId.NewObjectId().ToString(), document);
} /// <summary>
/// 保存文档
/// </summary>
/// <typeparam name="TDocument">文档类型</typeparam>
/// <param name="id">文档ID</param>
/// <param name="document">文档对象</param>
/// <returns>文档ID</returns>
public virtual string Save<TDocument>(string id, TDocument document)
{
if (string.IsNullOrEmpty(id))
throw new ArgumentNullException("id"); if (document == null)
throw new ArgumentNullException("document"); Delete<TDocument>(id); try
{
string fileName = GenerateFileFullPath<TDocument>(id);
string output = Serialize(document); lock (operationLock)
{
System.IO.FileInfo info = new System.IO.FileInfo(fileName);
System.IO.Directory.CreateDirectory(info.Directory.FullName);
System.IO.File.WriteAllText(fileName, output);
}
}
catch (Exception ex)
{
throw new FileDatabaseException(
string.Format(CultureInfo.InvariantCulture,
"Save document failed with id [{0}].", id), ex);
} return id;
} /// <summary>
/// 根据文档ID查找文档
/// </summary>
/// <typeparam name="TDocument">文档类型</typeparam>
/// <param name="id">文档ID</param>
/// <returns>文档对象</returns>
public virtual TDocument FindOneById<TDocument>(string id)
{
if (string.IsNullOrEmpty(id))
throw new ArgumentNullException("id"); try
{
string fileName = GenerateFileFullPath<TDocument>(id);
if (File.Exists(fileName))
{
string fileData = File.ReadAllText(fileName);
return Deserialize<TDocument>(fileData);
} return default(TDocument);
}
catch (Exception ex)
{
throw new FileDatabaseException(
string.Format(CultureInfo.InvariantCulture,
"Find document by id [{0}] failed.", id), ex);
}
} /// <summary>
/// 查找指定类型的所有文档
/// </summary>
/// <typeparam name="TDocument">文档类型</typeparam>
/// <returns>文档对象序列</returns>
public virtual IEnumerable<TDocument> FindAll<TDocument>()
{
try
{
string[] files = System.IO.Directory.GetFiles(
GenerateFilePath<TDocument>(),
"*." + FileExtension,
SearchOption.TopDirectoryOnly); List<TDocument> list = new List<TDocument>();
foreach (string fileName in files)
{
string fileData = File.ReadAllText(fileName);
TDocument document = Deserialize<TDocument>(fileData);
if (document != null)
{
list.Add(document);
}
} return list;
}
catch (Exception ex)
{
throw new FileDatabaseException(
"Find all documents failed.", ex);
}
} /// <summary>
/// 根据指定文档ID删除文档
/// </summary>
/// <typeparam name="TDocument">文档类型</typeparam>
/// <param name="id">文档ID</param>
public virtual void Delete<TDocument>(string id)
{
if (string.IsNullOrEmpty(id))
throw new ArgumentNullException("id"); try
{
string fileName = GenerateFileFullPath<TDocument>(id);
if (File.Exists(fileName))
{
lock (operationLock)
{
File.Delete(fileName);
}
}
}
catch (Exception ex)
{
throw new FileDatabaseException(
string.Format(CultureInfo.InvariantCulture,
"Delete document by id [{0}] failed.", id), ex);
}
} /// <summary>
/// 删除所有指定类型的文档
/// </summary>
/// <typeparam name="TDocument">文档类型</typeparam>
public virtual void DeleteAll<TDocument>()
{
try
{
string[] files = System.IO.Directory.GetFiles(
GenerateFilePath<TDocument>(), "*." + FileExtension,
SearchOption.TopDirectoryOnly); foreach (string fileName in files)
{
lock (operationLock)
{
File.Delete(fileName);
}
}
}
catch (Exception ex)
{
throw new FileDatabaseException(
"Delete all documents failed.", ex);
}
} /// <summary>
/// 获取指定类型文档的数量
/// </summary>
/// <typeparam name="TDocument">文档类型</typeparam>
/// <returns>文档的数量</returns>
public virtual int Count<TDocument>()
{
try
{
string[] files = System.IO.Directory.GetFiles(
GenerateFilePath<TDocument>(),
"*." + FileExtension, SearchOption.TopDirectoryOnly);
if (files != null)
{
return files.Length;
}
else
{
return ;
}
}
catch (Exception ex)
{
throw new FileDatabaseException(
"Count all documents failed.", ex);
}
} #endregion #region Protected Methods /// <summary>
/// 生成文件全路径
/// </summary>
/// <typeparam name="TDocument">文档类型</typeparam>
/// <param name="id">文档ID</param>
/// <returns>文件路径</returns>
protected virtual string GenerateFileFullPath<TDocument>(string id)
{
return Path.Combine(GenerateFilePath<TDocument>(),
GenerateFileName<TDocument>(id));
} /// <summary>
/// 生成文件路径
/// </summary>
/// <typeparam name="TDocument">文档类型</typeparam>
/// <returns>文件路径</returns>
protected virtual string GenerateFilePath<TDocument>()
{
return Path.Combine(this.Directory, typeof(TDocument).Name);
} /// <summary>
/// 生成文件名
/// </summary>
/// <typeparam name="TDocument">文档类型</typeparam>
/// <param name="id">文档ID</param>
/// <returns>文件名</returns>
protected virtual string GenerateFileName<TDocument>(string id)
{
if (string.IsNullOrEmpty(id))
throw new ArgumentNullException("id"); foreach (char c in id)
{
if (invalidFileNameChars.Contains(c))
{
throw new FileDatabaseException(
string.Format(CultureInfo.InvariantCulture,
"The character '{0}' is not a valid file name identifier.", c));
}
} return string.Format(CultureInfo.InvariantCulture, "{0}.{1}", id, FileExtension);
} /// <summary>
/// 将指定的文档对象序列化至字符串
/// </summary>
/// <param name="value">指定的文档对象</param>
/// <returns>文档对象序列化后的字符串</returns>
protected abstract string Serialize(object value); /// <summary>
/// 将字符串反序列化成文档对象
/// </summary>
/// <typeparam name="TDocument">文档类型</typeparam>
/// <param name="data">字符串</param>
/// <returns>文档对象</returns>
protected abstract TDocument Deserialize<TDocument>(string data); #endregion
}

XML文件数据库实现

   /// <summary>
/// XML文件数据库
/// </summary>
public class XmlDatabase : FileDatabase
{
/// <summary>
/// XML文件数据库
/// </summary>
/// <param name="directory">数据库文件所在目录</param>
public XmlDatabase(string directory)
: base(directory)
{
FileExtension = @"xml";
} /// <summary>
/// 将指定的文档对象序列化至字符串
/// </summary>
/// <param name="value">指定的文档对象</param>
/// <returns>
/// 文档对象序列化后的字符串
/// </returns>
protected override string Serialize(object value)
{
if (value == null)
throw new ArgumentNullException("value"); using (StringWriterWithEncoding sw = new StringWriterWithEncoding(Encoding.UTF8))
{
XmlSerializer serializer = new XmlSerializer(value.GetType());
serializer.Serialize(sw, value);
return sw.ToString();
}
} /// <summary>
/// 将字符串反序列化成文档对象
/// </summary>
/// <typeparam name="TDocument">文档类型</typeparam>
/// <param name="data">字符串</param>
/// <returns>
/// 文档对象
/// </returns>
protected override TDocument Deserialize<TDocument>(string data)
{
if (string.IsNullOrEmpty(data))
throw new ArgumentNullException("data"); using (StringReader sr = new StringReader(data))
{
XmlSerializer serializer = new XmlSerializer(typeof(TDocument));
return (TDocument)serializer.Deserialize(sr);
}
}
}

JSON文件数据库实现

   /// <summary>
/// JSON文件数据库
/// </summary>
public class JsonDatabase : FileDatabase
{
/// <summary>
/// JSON文件数据库
/// </summary>
/// <param name="directory">数据库文件所在目录</param>
public JsonDatabase(string directory)
: base(directory)
{
FileExtension = @"json";
} /// <summary>
/// 将指定的文档对象序列化至字符串
/// </summary>
/// <param name="value">指定的文档对象</param>
/// <returns>
/// 文档对象序列化后的字符串
/// </returns>
protected override string Serialize(object value)
{
if (value == null)
throw new ArgumentNullException("value"); return JsonConvert.SerializeObject(value, OutputIndent);
} /// <summary>
/// 将字符串反序列化成文档对象
/// </summary>
/// <typeparam name="TDocument">文档类型</typeparam>
/// <param name="data">字符串</param>
/// <returns>
/// 文档对象
/// </returns>
protected override TDocument Deserialize<TDocument>(string data)
{
if (string.IsNullOrEmpty(data))
throw new ArgumentNullException("data"); return JsonConvert.DeserializeObject<TDocument>(data);
}
}

Test Double

   [Serializable]
public class Cat
{
public Cat()
{
Id = ObjectId.NewObjectId().ToString();
} public Cat(string id)
{
Id = id;
} public string Name { get; set; }
public int Legs { get; set; } public string Id { get; set; } public override string ToString()
{
return string.Format("DocumentId={0}, Name={1}, Legs={2}", Id, Name, Legs);
}
}

使用举例

   class Program
{
static void Main(string[] args)
{
TestJsonDatabase();
TestXmlDatabase(); Console.ReadKey();
} private static void TestJsonDatabase()
{
JsonDatabase db = new JsonDatabase(@"C:\tmp");
db.OutputIndent = true; Cat origin = new Cat() { Name = "Garfield", Legs = };
db.Save<Cat>(origin); db.Save<Cat>(origin.Id, origin);
db.Delete<Cat>(origin.Id);
} private static void TestXmlDatabase()
{
XmlDatabase db = new XmlDatabase(@"C:\tmp");
db.OutputIndent = true; Cat origin = new Cat() { Name = "Garfield", Legs = };
db.Save<Cat>(origin); db.Save<Cat>(origin.Id, origin);
db.Delete<Cat>(origin.Id);
}
}

C#实现文件数据库的更多相关文章

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

    小型文件数据库 (a file database for small apps) SharpFileDB For english version of this article, please cli ...

  2. .NET平台开源项目速览(3)小巧轻量级NoSQL文件数据库LiteDB

    今天给大家介绍一个不错的小巧轻量级的NoSQL文件数据库LiteDB.本博客在2013年也介绍过2款.NET平台的开源数据库: 1.[原创]开源.NET下的XML数据库介绍及入门 2.[原创]C#开源 ...

  3. C#实现XML文件数据库存储

    C#实现文件数据库 http://www.cnblogs.com/gaochundong/archive/2013/04/24/csharp_file_database.html#3100076 应用 ...

  4. Linux在什么样的从脚本文件数据库sh格式改变sql格式

    在软件开发过程中,经常参与Linux从下一个脚本文件数据库sh格式改变sql格式问题.在本文中,一个实际的脚本文件,例如.描述格式转换过程.        1. sh文件内容 本文中的文件名称为exa ...

  5. sqlite内存数据库和文件数据库的同步[转]

    由于sqlite对多进程操作支持效果不太理想,在项目中,为了避免频繁读写 文件数据库带来的性能损耗,我们可以采用操作sqlite内存数据库,并将内存数据库定时同步到文件数据库中的方法. 实现思路如下: ...

  6. 07 部署fastDFS文件数据库

    安装fastDFS前必须准备好两个版本匹配的文件: libfastcommon_V1.0.7.tar.gz:基础库文件 FastDFS_V5.05.tar.gz:文件数据库文件 注:这两个文件版本要匹 ...

  7. JAVA 操作 DBF 文件数据库

    1.依赖夹包 javadbf-[].4.1.jar jconn3.jar 2.添加属性文件 jdbc.properties jdbc.driverClassName=com.sybase.jdbc3. ...

  8. java POI导出Excel文件数据库的数据

    在web开发中,有一个经典的功能,就是数据的导入导出.特别是数据的导出,在生产管理或者财务系统中用的非常普遍,因为这些系统经常要做一些报表打印的工作.这里我简单实现导出Excel文件. POI jar ...

  9. c#聊聊文件数据库kv

    现在有很多KV嵌入式存储,或者已经增加的.leveldb,RaptorDB等,都是相对比较好的存储.基本存储,一般配置.大概在6w/s左右.当然还有缓存等设置问题.这些基本是字符串和int的存储,对于 ...

随机推荐

  1. 工厂方法模式(Factory Method)

    1.本质:延迟到子类来选择实现 2.示意图: 3.主要功能: 让父类在不知道具体实现的情况下,完成自身功能的调用 类似于注入 4.备注: 1.工厂方法中,通常父类是一个抽象类,里面包含创建对象的抽象工 ...

  2. Linux常用命令大全(2)

    系统信息arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 - (SMBIOS / ...

  3. uboot使用tftp下载时出现“checksum bad”问题原因分析

    一.问题 二.原因分析 你的虚拟机是不是这样设置的呢? 如果是的话,请看下边的解释: 使用NAT模式,就是让虚拟系统借助NAT(网络地址转换)功能,通过宿主机器所在的网络来访问公网.也就是说,使用NA ...

  4. 知识库系统/知识管理系统 WCP

    知识库系统/知识管理系统 WCP 本项目的应用场景是管理技术团队的相关知识(API.代码片段.知识定义.技术经验...) 但是其应用并不局限于这些应用,当然你最好下载一个安装版先试一试.其实这就是一个 ...

  5. oracle常见sql积累

    select lower('HELLO') from dual;select lpad(100, 5, '*') from dual;select sysdate + 1 / 24 from dual ...

  6. 转 四大Java EE容器(Tomcat、JBoss、Resin、Glassfish)之简单比较

                                      现在流行的Java EE容器有很多:Tomcat.JBoss.Resin.Glassfish等等.下面对这四种Java EE容器进行 ...

  7. 强制不使用“兼容性视图”的HTML代码(转)

    在IE8浏览器以后版本,都有一个“兼容性视图”,让不少新技术无法使用.那么如何禁止浏览器自动选择“兼容性视图”,强制IE以最高级别的可用模式显示内容呢?下面就介绍一段HTML代码. X-UA-Comp ...

  8. 转:Google技术开发指南:给大学生自学的建议

    原文来自于:http://blog.jobbole.com/80621/ 技术开发指南 想要成为成功的软件工程师,必须拥有坚实的计算机科学的基础.本指南针对大学生,给出一条自学途径,让学生以科班和非科 ...

  9. Catharanthus roseus(长春花碱)的生物合成

    标题:Directed Biosynthesis of Alkaloid Analogs in the Medicinal Plant Catharanthus roseus 作者:Elizabeth ...

  10. [BZOJ 1026] [SCOI 2009] Windy数 【数位DP】

    题目链接:BZOJ - 1026 题目分析 这道题是一道数位DP的基础题,对于完全不会数位DP的我来说也是难题.. 对于询问 [a,b] 的区间的答案,我们对询问进行差分,求 [0,b] - [0,a ...