如何在 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 标志打​​开文件?的主要内容,如果未能解决你的问题,请参考以下文章

C#如何打开文件进行写入并允许其他人读取它

ava如何追加写入txt文件

java如何追加写入txt文件

如何使用 fs.appendFile() 追加文件但不写入另一个 JSON 对象

C#文件写入操作

如何在 C# 中使用 MSMQ