1

我想打开一个文本文件,并且不允许任何其他进程写入它。我知道我可以使用以下 FileStream 做到这一点:

Dim fs As New FileStream(_FilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.Read)

一旦我有这样的访问权限,我需要读取所有行(我将使用 StreamReader(fs)),然后我需要写入文件(我将使用 StreamWriter(fs))。

这里的问题是,当我使用文件流作为参数而不是文件路径时,StreamWriter 不允许我将附加模式设置为 false(这样我就可以覆盖文件中的所有文本)。因此,使用 StreamWriter 编写的所有文本都附加到我不想要的文本上。如果我使用带有文件路径的 StreamWriter(这将使我将 append 设置为 false)作为参数而不是文件流,它将因为 FileStream FileShare 而被锁定。我怎样才能仍然拥有读取和写入文件的独占访问权限,但仍然能够覆盖现有文本(附加模式为 false)?

4

1 回答 1

2

这并非不可能,您实际上不需要使用 Apppend = true 初始化的 StreamWriter。您需要做的就是使用 FileStream.Seek() 来确保“文件指针”位于文件末尾。此示例 C# 代码运行良好:

using (var fs = new FileStream(@"c:\temp\test.txt", FileMode.Open,
        FileAccess.ReadWrite, FileShare.Read)) {
    var sr = new StreamReader(fs);   // NOTE: not using using
    string txt = sr.ReadToEnd();
    fs.Seek(0, SeekOrigin.End);      // Be sure
    var sw = new StreamWriter(fs);
    sw.WriteLine("appended");
    sw.Flush();
}

请注意此代码中相当多的不适。我将从您的首选值 FileShare.Read 开始。这意味着您将在修改文件时让另一个进程读取该文件。这个过程很有可能会在没有通知的情况下对这个文件中出现的字节感到有点困惑。可以很好地工作,FileShare.None 确保您的代码永远不会导致任何类型的事故。强力推荐。

下一个标志是 // 注意不使用 using。这很重要,因为 StreamReader 将对您传递的流承担“责任”。如果您在 .NET 代码中执行标准的正确操作,则该类将在 Using 语句结束其范围时关闭流。这不是你想要的,你想保留文件以便你可以写入它。

Seek() 调用执行 StreamWriter 构造函数的 Append 参数所做的事情,确保您附加到文件,而不是从头开始随机覆盖文件的某些部分。由于您要追加,因此确保文件中的旧数据被截断没有问题。

Flush 调用是这里的臭味。您必须调用它来强制编写器刷新其输出缓冲区。如果你不这样做,你写的内容的随机位将从文件中丢失。这通常不是问题,因为您会调用 Close() 或使用 Using 语句来确保编写器已关闭。不是在这种情况下,FileStream 正在发号施令,它会在此处正确关闭文件,但它不知道另一个作家加入了潮流并想要写入。

这将起作用,但它打破了相当多的教条。更典型的模式是 open-read + read + close,open-createnew + write + close。并处理 open-createnew 可能因另一个进程抓取文件而失败的可能性。多任务操作系统的危害,始终准备好应对。

于 2010-10-20T22:19:22.440 回答