如何在 C# 中进行原子写入/追加,或者如何使用 FILE_APPEND_DATA 标志打开文件?
Posted
技术标签:
【中文标题】如何在 C# 中进行原子写入/追加,或者如何使用 FILE_APPEND_DATA 标志打开文件?【英文标题】:How can I do an atomic write/append in C#, or how do I get files opened with the FILE_APPEND_DATA flag? 【发布时间】:2010-12-24 03:43:04 【问题描述】:在大多数符合 Unix 和 Posix 的操作系统下,使用 O_APPEND 执行 open() 操作系统调用向操作系统指示写入是原子追加和写入操作。通过这种行为,对于本地文件系统,当您进行写入时,您知道它会附加到文件末尾。
Windows 操作系统通过将适当的参数中的FILE_APPEND_DATA
传递给 Win32 CreateFile() 系统调用来支持相同的功能。
参考:
http://www.google.com/search?q=msdn+createfile
or: http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx
http://www.google.com/search?q=msdn+IoCreateFileSpecifyDeviceObjectHint
or: http://www.google.com/search?q=msdn+IoCreateFileSpecifyDeviceObjectHint
我的问题是,我无法确定如何在 C# 下使用 Net Framework 获得这种行为 图书馆,有没有办法使用网络框架获得这种行为? 顺便说一句,我不相信使用 FileMode.Append 会产生这种行为。
【问题讨论】:
【参考方案1】:使用FileStream
构造函数的重载之一:
new FileStream(FileName, FileMode.Open, FileSystemRights.AppendData,
FileShare.Write, 4096, FileOptions.None)
FileSystemRights.AppendData
对应FILE_APPEND_DATA
FileStream 似乎坚持缓冲,因此请确保缓冲区足够大以容纳每个
在每次写入后写入并调用Flush()
。
小例子:
private void button1_Click(object sender, EventArgs e)
Thread t1 = new Thread(DoIt);
Thread t2 = new Thread(DoIt);
t1.Start("a");
t2.Start("b");
Thread.Sleep(2000);
Environment.Exit(0);
private void DoIt(object p)
using (FileStream fs = new FileStream(FileName, FileMode.Open, FileSystemRights.AppendData,
FileShare.Write, 4096, FileOptions.None))
using (StreamWriter writer = new StreamWriter(fs))
writer.AutoFlush = true;
for (int i = 0; i < 20; ++i)
writer.WriteLine("0: 1:D3 2:o hello", p, i, DateTime.Now);
【讨论】:
和使用File.AppendText
API一样吗?
FileStream 构造函数的最后一个参数,'bufferSize',或在本例中为 4096 将是原子写入长度的上限。
显然 FileSystemRights 不在 dotnetstandard 2.0 中。
使用 FileMode.Append 还是 FileMode.Open 有关系吗?如果文件不存在,Open 不会创建文件【参考方案2】:
您可以使用带有所需参数的PInvoke 调用CreateFile,并将生成的句柄传递给FileStream Constructors 之一,该FileStream Constructors 将SafeFileHandle 作为参数。
【讨论】:
【参考方案3】:为什么不能用
System.IO.File.AppendAllText("C:\\somefile.txt", "some content");
?这也是一个线程安全/“原子”调用。
【讨论】:
不幸的是,这并没有提供我正在寻找的进程级原子操作。 当多个线程访问文件时,如果文件被另一个进程使用,则抛出 IOException。以上是关于如何在 C# 中进行原子写入/追加,或者如何使用 FILE_APPEND_DATA 标志打开文件?的主要内容,如果未能解决你的问题,请参考以下文章