【问题标题】:How do you persist data to disk from .NET?如何将数据从 .NET 持久化到磁盘?
【发布时间】:2011-02-02 04:00:45
【问题描述】:

我有各种丰富的数据结构(主要是树),我想将它们保存到磁盘,这意味着我不仅想将它们写入磁盘,而且我想保证数据已经完全写入并且能够在掉电。

其他人似乎设计了将平面数据库表中的丰富数据结构编码为从父节点到子节点的查找表的方法。这有助于对数据运行 SQL 查询,但我不需要这样做:我只想保存和加载我的树。

显而易见的解决方案是将所有内容作为 blob 存储在数据库中:单个条目可能包含一个长字符串。这是对数据库的滥用还是推荐的做法?另一种解决方案可能是使用 XML 数据库?有没有我应该考虑的数据库替代品?

最后,我是从 F# 执行此操作的,因此从 .NET 持久化数据的交钥匙解决方案将是理想的...

编辑:请注意,格式(例如序列化)是无关紧要的,因为我可以使用 F# 在格式之间进行简单的转换。这是关于确认写入已完成,一直到非易失性存储(即磁盘盘片),并且写入数据的任何部分都没有仍然保存在易失性存储(例如 RAM 缓存)中,以便我可以继续安全地了解这些知识(例如,通过从磁盘中删除旧版本的数据)。

【问题讨论】:

  • 重新“交钥匙解决方案” - 一些(不是全部)F# 构造可能超出了许多持久层所期望的 典型 窗口 - 将使用 DTO 类层(就在之前到序列化)如果它简化了事情是否可以接受?另外 - 我怀疑您可能想分别查看 serializationACID 方面。
  • 如果(查看您对 Reed 的评论)序列化方面不是问题,那么可能是任何 ACID document 数据库。
  • @Marc:“ACID 文档数据库”。太棒了,谢谢!
  • 随机建议; Raven DB 可能值得一看

标签: c# .net database f# persistence


【解决方案1】:

.NET 的 FileStream 类的一些构造函数采用FileOptions 类型的参数。 FileOptions 的值之一是 WriteThrough,它“指示系统应该通过任何中间缓存写入并直接进入磁盘。”

这应确保在您的写入操作(对新文件)返回时,数据已提交到磁盘,您可以安全地删除旧文件。

【讨论】:

  • 感谢您的回答。我从来不知道这些文件选项的存在:WriteThrough、Asynchronous、RandomAccess、DeleteOnClose、SequentialScan 和 Encrypted。研究它们中的每一个可能值得一篇好的博文。
【解决方案2】:

这可以通过Serialization 完成。

.NET Framework 包含许多用于将数据序列化到磁盘的内置选项,包括使用二进制或基于 XML 的格式。 MSDN 文档中提供了详细的How-To articles

【讨论】:

  • @Jon Harrop:序列化与格式化无关——它与持久性有关。 “序列化是将对象的状态转换为可以持久化或传输的形式的过程。”来自:msdn.microsoft.com/en-us/library/7ay27kt9.aspx
  • @Jon Harrop:您可以使用 DataContractSerializer 序列化对象层次结构并将流直接保存到磁盘,然后稍后重新加载...这就是序列化的全部意义。
  • @Reed:我很清楚什么是序列化。我的观点是,它与关于保证磁盘持久性的问题完全无关。您如何“将流直接保存到磁盘”以便即使在保存过程中途断电的情况下也能保证一致性?序列化与此无关,只是格式的改变。
  • @Darin:硬件故障也完全无关紧要。如果我听从 Reed 的建议并使用简单的序列化到磁盘,那么在写入过程中关闭将给我留下静默损坏的数据。这显然对我没用。这是基本的数据库功能,不是科幻小说。
  • @kvb:我可以使用多种技术中的任何一种来更改数据的格式,但这与确保其持久性到磁盘的一致性无关。
【解决方案3】:

为了做到这一点,您需要一个资源,可以让您参与Transaction(通常情况下,您会使用TransactionScope

如果包含Transaction,大多数数据库将参与其中。磁盘操作也可以由Transaction 管理,但您必须做一些specific work in order to utilize it in .NET

另外,请注意,这仅适用于 Windows Vista 及更高版本。

如果您使用数据库路线,那么您可以将树的序列化内容存储在一个 blob(或文本,取决于序列化机制)中。

注意,您还可以使用 SQL Server(我相信 2008 及更高版本)中的 FILESTREAM 功能将您的文件存储在文件系统上获得 SQL Server 中事务的好处。

【讨论】:

    【解决方案4】:

    我之前没有使用过 F# 中的 db4o,但这完全是关于以事务方式将 CLR 对象图保存到磁盘。如果它适用于记录和歧视性工会,它可能适合您。

    编辑:我刚刚测试了 db4o 8.0(.NET 4 版本),它似乎可以很好地处理记录类型和可区分的联合层次结构。

    【讨论】:

      【解决方案5】:

      尝试使用 XMLSerializer (System.Xml.Serialization)。

      http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx

      它可以根据属性自动持久化复杂的数据结构,如果你愿意,你可以使用属性来控制输出:

      http://msdn.microsoft.com/en-us/library/83y7df3e.aspx

      【讨论】:

      • XMLSerializer 不适用于多种 F# 类型,尤其是记录和可区分联合,因为它们没有默认的无参数实例构造函数。这是不幸的,因为有区别的联合提供了一种很好的建模树的方法。二进制序列化是最直接的方法。
      • @C. Lawrence Wenham:这个关于格式化的答案与我关于保证磁盘持久性的问题有什么关系? XML 序列化程序和任何其他序列化程序都没有做出这样的保证,AFAIK。
      • 没有什么可以保证写入磁盘,您需要事后检查没有异常,文件存在并且不是零字节。您可以在自定义类中实现 System.Transactions.IEnlistmentNotification,该类将在可分发事务中登记您的写入,如果写入失败,您可以回滚其他操作
      • @C. Lawrence Whenham:没有任何东西可以保证写入磁盘的说法有些不正确。事务型 NTFS 从 Vista 开始就已经存在,所以虽然不能保证写入磁盘,但可以保证与磁盘交互时的原子操作。
      • C. Lawrence Wenham:我说的是保证它已经完成是一种承认,而不是它会完成。使用同样不提供此类保证的 API 检查文件有效性显然不能解决问题:一些数据可能仍位于易失性写入缓冲区中,等待写入盘片。数据库提供了这样的数据一致性保证,但我只需要保留二进制 blob,不一定是关系数据。
      【解决方案6】:

      由于 OP 不想要 XML,所以有点 OT,但看到其他人提到了 XML 格式化程序...... 如果您想要文本持久性,SoapFormatter 处理案例 (循环/对象图)默认 XML 格式化程序没有 - 它的 XML 不像 XMLFormatter 那样可读,但它比二进制更具可读性:)

      【讨论】:

        猜你喜欢
        • 2020-10-08
        • 1970-01-01
        • 1970-01-01
        • 2013-02-14
        • 1970-01-01
        • 2018-01-21
        • 2022-01-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多