10

我有多个 Windows 程序(在 Windows 2000、XP 和 7 上运行),它们处理不同格式的文本文件(csv、tsv、ini 和 xml)。在文件 IO 期间不要损坏这些文件的内容非常重要。每个文件都应该可以被多个程序同时安全地访问,并且应该能够防止系统崩溃。这个 SO 答案建议使用进程内数据库,所以我正在考虑使用Microsoft Jet Database Engine,它能够处理分隔文本文件(csv、tsv)并支持事务. 我之前用过Jet,但不知道Jet事务是否真的能容忍提交阶段的意外崩溃或关机,也不知道如何处理非分隔文本文件(ini、xml)。我认为尝试手动实现完全 ACIDic 文件 IO 不是一个好主意。

在 Windows 上实现文本文件事务处理的最佳方法是什么?我必须能够在 Delphi 和 C# 中做到这一点。

提前谢谢你的帮助。

编辑

让我们看一个基于@SirRufo 想法的示例。暂时忘记并发,让我们专注于崩溃容错。

  1. 我将文件的内容读入数据结构以修改某些字段。当我正在将修改后的数据写回文件时,系统可能会崩溃。

  2. 如果我从不将数据写回原始文件,则可以避免文件损坏。这可以通过创建一个新文件来轻松实现,每次保存修改时文件名中都有一个时间戳。但这还不够:原始文件将保持不变,但新写入的文件可能已损坏。

  3. 我可以通过在时间戳后面加上一个“0”字符来解决这个问题,这意味着该文件尚未经过验证。我将通过验证步骤结束写入过程:我将读取新文件,将其内容与我试图保存的内存结构进行比较,如果它们相同,则将标志更改为“1”。每次程序必须读取文件时,它都会通过比较文件名中的时间戳来选择最新版本。只能保留最新版本,旧版本可以删除。

  4. 并发可以通过在读取或写入文件之前等待命名互斥体来处理。当程序获得对文件的访问权时,它必须从检查文件名列表开始。如果它想读取文件,它将读取最新版本。另一方面,只有在没有比上次读取的版本更新的版本时才能开始写入。

这是一种粗略、过于简单且效率低下的方法,但它显示了我的想法。写入文件是不安全的,但也许有像上面这样的简单技巧可以帮助避免文件损坏。

更新

用 Java 编写的开源解决方案:

4

6 回答 6

6

使用 NTFS 文件流怎么样?将多个命名(编号/时间戳)流写入相同的文件名。每个版本都可以存储在不同的流中,但实际上存储在同一个“文件”或一堆文件中,保留数据并提供回滚机制......当您达到确定点时,删除一些以前的流.

在新台币 4 中引入?它涵盖了所有版本。应该是防崩溃的,您将始终拥有以前的版本/流以及要恢复/回滚的原始版本。

只是深夜的想法。

http://msdn.microsoft.com/en-gb/library/windows/desktop/aa364404%28v=vs.85%29.aspx

于 2012-12-10T22:39:31.717 回答
4

您要求的是事务性,如果不根据您的要求开发自己的 RDBMS 数据库机制,这是不可能的:

“在文件 IO 期间不要破坏这些文件的内容非常重要”

拿起一个 DBMS。

于 2012-12-09T23:27:23.400 回答
1

请参阅相关文章Accessing a single file with multiple threads 但是我的意见是使用 Raven DB 之类的数据库进行此类事务,Raven DB 支持对同一文件的并发访问以及支持将多个操作批处理到单个请求中。但是,所有内容都作为 JSON 文档保存,而不是文本文件。它确实很好地支持 .NET/C#,包括 Javascript 和 HTML,但不支持 Delphi。

于 2012-12-07T11:25:28.567 回答
1

首先,这个问题与 C# 或 Delphi 无关。您必须模拟您的文件结构,就好像它是一个数据库一样。

假设;

  • 移动文件是一个廉价的过程,并且 Op System 保证文件在移动过程中不会损坏。

  • 您有一个需要处理的文件目录。(d:\filesDB*.*)

  • 控制器应用程序是必须的。

简化的工作流程;

-初始化

  1. 从操作系统获取 processID。
  2. 在 d:\filesDB 中创建目录

    d:\filesDB\<processID>
    d:\filesDB\<processID>\inBox
    d:\filesDB\<processID>\outBox
    

-处理每个文件

  1. 选择要处理的文件。
  2. 将其移动到“收件箱”目录(确保对文件的单一访问)
  3. 打开文件
  4. 在“outBox”中创建新文件并正确关闭
  5. 删除“收件箱”目录中的文件。
  6. 将位于“OutBox”中的新创建文件移回 d:\filesDB

-定稿

  1. 删除创建的目录。

控制器应用

仅在系统启动时运行,并初始化将完成工作的应用程序。

  1. 扫描 d:\filesDB 目录的子目录,
  2. 对于每个子目录 2.1,如果文件存在于“inBox”中,则将其移动到 d:\filesDB 并跳过“outBox”。2.2 如果文件存在于“outBox”中,将其移动到d:\filesDB 2.3 删除整个子目录。
  3. 启动每个需要启动的工作进程。

我希望这能解决你的问题。

于 2012-12-10T15:06:10.723 回答
1

您正在为自己创造一场噩梦,试图在您自己的代码中跨多个系统处理这些事务和状态。这就是为什么拉里·埃里森(甲骨文首席执行官)是亿万富翁,而我们大多数人都不是。如果您绝对必须使用文件,则设置支持 LOB 和 CLOB 对象的 Oracle 或其他数据库。我为我的公司将非常大的 SVG 文件存储在这样的表中,这样我们就可以在我们的系统中添加和渲染大型地图,而无需更改任何代码。可以从表中提取文件并在缓冲区中传递给您的用户,然后在完成后返回数据库。设置适当的安全和记录锁定,您的问题就解决了。

于 2012-12-15T04:33:06.623 回答
0

好吧,你死了——除非你能放弃 XP。就这么简单。

由于 POST-XP Windows 支持 Transactional NTFS——尽管它没有暴露给 .NET(本机——你仍然可以使用它)。这允许用户在 NTFS 文件系统上回滚或提交更改,甚至可以与数据库协调使用 DTC。挺好的。XP,虽然- 没办法,不在那里。

任何真实世界的企业级交易 NTFS (TxF) 体验开始?作为首发。那里的问题列出了很多资源,让您开始了解如何去做。

请注意,这确实有性能开销 - 显然。不过,这并不是那么糟糕,除非您需要第二个事务资源,因为那里有一个非常薄的内核级事务协调器,只有在添加第二个资源时,事务才会被提升为完整的 DTC。

对于直接链接 - http://msdn.microsoft.com/en-us/magazine/cc163388.aspx有一些很好的信息。

于 2012-12-08T19:01:42.890 回答