如何在 C# 中锁定文件而不使其在首次读取后不可写?

How do you lock a file in C# without making it unwritable after first being read?

这个问题源于另一个线程:How to lock a file with C#?

基本上假设您要锁定一个 JSON 文件,读取它,然后写入它,最后解锁它。您可以使用其他问题的答案锁定文件。

但是我遇到了问题,这允许我读取文件,但在没有先解锁文件的情况下不能写入文件。也就是说,推荐的方法,似乎相当受人尊敬,是将同一个线程锁定在它自己的资源之外.

示例:

using (var fs = new FileStream(GetJsonPath(), FileMode.Open, FileAccess.ReadWrite,
        FileShare.None))
{
    SomeDtoType dto;
    using (StreamReader reader = new StreamReader(fs))
    {
        dto = ((SomeDtoType)(new JsonSerializer()).Deserialize(reader,
                typeof(SomeDtoType)));
    }

    // Make changes to the DTO.....

    using (StreamWriter writer = new StreamWriter(fs))
    {
        new JsonSerializer().Serialize(writer, dto);
    }
}

创建 StreamWriterusing 行抛出以下异常:

Stream was not writable.

现在想到的一件事是 FileShare.None 的值。这里的问题是那个特定的枚举显然不仅仅是为外部进程设置锁定权限。

如何将外部 threads/processes 锁定在 changing/deleting 文件之外,同时允许您自己进行这两个后续 read/write 访问?

编辑:

显然将所有内容都移到 StreamReaderusing 块中,然后在读取和写入类型之间将 fs.Position 设置为 0 可以解决此问题。 fs.Position 部分很好,但是必须将写入逻辑移动到 StreamReaderusing 块中,这样它们才能使用相同的 FileStream 锁,这似乎是有点奇怪...

StreamReader 如果您不使用 ctor 重载并指示它不要这样做,则关闭流:

using (StreamReader reader = new StreamReader(fs, Encoding.UTF8, true, 4096, leaveOpen:true))

StreamReader 中没有终结器,您可以将其移出 using 块并保持未处理状态,但我建议明确控制生命周期和行为。

另一个问题是您将追加到文件中。如果你想覆盖一个内容,你需要在写入之前重置它:

fs.SetLength(0);