简体   繁体   中英

After StreamWriter.WriteLine(), FileStream.SetLength(0) does not empty the file

I found a strange problem with FileStream.SetLength(0). When writing first something to a stream and then calling SetLength(0), the content of the previous write still gets written to the file:

var fileName = "test.txt";
using (var fileStream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, 8000, FileOptions.None)) 
{
    using (var streamWriter = new StreamWriter(fileStream, Encoding.Default, bufferSize: 8000, leaveOpen: true)) 
    {
        streamWriter.WriteLine("123");
        fileStream.SetLength(0);
        streamWriter.WriteLine("abc");
    }
}
  var fileContent = File.ReadAllText(fileName);

fileContent becomes "123\\r\\nabc\\r\\n"

Obviously, 123 did not get deleted, even it was written before calling SetLength(0).

Using Seek() or setting the Position to 0 did not help.

In my application, I am writing to a file, which I keep open. From time to time it can happen that I need to empty the file completely and write a different content. For performance reasons, I don't want to close the streamWriter.

Note to all those guys who love to mark wrongly questions as duplicates

I made the very frustrating experience on Stackoverflow that a question got marked wrongly as duplicate. I spent a day writing the question, he decides in an instant that it's a duplicate, even when it isn't. This usually happens when that guy doesn't truly understand the question and doesn't bother to find the correct answer. He just feels that a similar problem was solved before on SO. But details matter. Yes, there are questions about truncating a file using SetLength(0), but they are different in one crucial point: In those examples, SetLength(0) is not preceded by a Write(). But this is essential, without it there is no problem.

Please, please, be very careful and considerate when blocking others from answering by marking a question as duplicate.

When inspecting FileStream.SetLength() on referencesource.microsoft.com , I noticed this funny looking piece of code:

        // Handle buffering updates.
        if (_writePos > 0) {
            FlushWrite(false);
        }

It checks within SetLength() if the internal FileStream buffer has still some write content and writes it first to the file, before executing the rest of SetLength().

A very strange behavior. I could solve this problem by emptying the internal buffer before calling SetLength() using a Flush() first:

  var fileName = "test.txt";
  using (var fileStream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, 8000, FileOptions.None)) {
    using (var streamWriter = new StreamWriter(fileStream, Encoding.Default, bufferSize: 8000, leaveOpen: true)) {
      streamWriter.WriteLine("123");
      streamWriter.Flush();
      fileStream.SetLength(0);
      streamWriter.WriteLine("abc");
    }
  }
  var fileContent = File.ReadAllText(fileName);

fileContent is now: "abc\\r\\n"

I would be interested to hear if also other feel this is a bug in FileStream ?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM