对文本文件的独占访问,读取和覆盖它

发布于 2024-09-28 01:34:09 字数 519 浏览 6 评论 0原文

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

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

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

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

I'd like to open a text file and not allow any other processes to write to it. I understand I can do this with the following FileStream:

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

Once I have access like this I need to read all of the lines (I will use a StreamReader(fs)) and then I will need to write to the file (I will use a StreamWriter(fs)).

The problem here is that the StreamWriter won't allow me to set the append mode to false (so I can overwrite all text in the file) when I use the filestream as a parameter instead of the file path. So all text written with the StreamWriter is appended onto the text which I don't want. If I use a StreamWriter with the file path (which will let me set append to false) as the parameter instead of the filestream it will be locked out because of the FileStream FileShare. How can I still have exclusive access to read and write to the file but still be able to overwrite the existing text (append mode false)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

浮光之海 2024-10-05 01:34:09

这并非不可能,您实际上不需要使用 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 可能因另一个进程获取该文件而失败的可能性。多任务操作系统的危害,请始终做好应对的准备。

It is not impossible, you don't actually need a StreamWriter initialized with Apppend = true. All you need to do is use FileStream.Seek() to ensure that the 'file pointer' is positioned at the end of the file. This sample C# code worked well:

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();
}

Do note the fair amount of discomfort in this code. I would start with FileShare.Read, your preferred value. It implies that you'll let another process read the file while you are tinkering with it. There are good odds that this process is going to get a bit confused about bytes showing up in this file without notice. Could work out well, FileShare.None ensures that your code can never cause any kind of mishap. Strongly recommended.

Next flag is // Note not using using. That's important because StreamReader will take 'responsibility' of the stream you pass it. If you do the standard Right Thing in .NET code, the class is going to close the stream when the Using statement ends its scope. That's not what you want, you want to keep a hold of the file so you can write to it.

The Seek() call does what the StreamWriter constructor's Append argument does, make really sure that you are appending to the file instead of randomly overwrite parts of the file from the beginning. Since you want to append, no problem about making sure that old data in the file is truncated.

The Flush call is the smelly bit here. You have to call it to force the writer to flush its output buffer. If you don't, random bits of what you write will be missing from the file. It is normally not a problem because you'd call Close() or use the Using statement to ensure the writer is closed. Not in this case, the FileStream is calling the shots, it will properly close the file here but it doesn't know that another writer jumped on the bandwagon and wants to write.

This will work but it breaks a fair number of dogmas. The more typical pattern is open-read + read + close, open-createnew + write + close. And dealing with the possibility that the open-createnew might in fail because another process grabbed the file. The hazards of a multi-tasking operating system, always be prepared to deal with that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文