0

I'm trying to replicate Excel's behaviour when opening and editing files, that is:

  • File is opened and locked for exclusive write access
  • Other users are allowed to read the file

I'm using the following code to open the file, read and prepare for later writing:

_fileStream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.Read);
_fileReader = new StreamReader(_fileStream);
_fileWriter = new StreamWriter(_fileStream);
var contents = _fileReader.ReadToEnd();

(In a class that implements IDisposable and disposes the streams)

It apparently works fine aside from one issue when I later save using the following code:

_fileWriter.BaseStream.Seek(0, SeekOrigin.Begin);
_fileWriter.Write(content);
_fileWriter.Flush();

The problem is that I need to truncate the file before saving, and the above only overwrites. If the new content is shorter than what was loaded, I end up with a bad file due to partial old content.

How do I truncate a filestream before writing (but not before reading)?

Is there perhaps a better way to gain exclusive access to the file than what I am doing?

Troels Larsen
  • 4,462
  • 2
  • 34
  • 54

1 Answers1

0

I don't know why I didn't think of this until now, but I found my answer in the source code for System.IO.File:

[SecurityCritical]
private static void InternalWriteAllText(
  string path,
  string contents,
  Encoding encoding,
  bool checkHost)
{
  using (StreamWriter streamWriter = new StreamWriter(path, false, encoding, 1024, checkHost))
    streamWriter.Write(contents);
}

I didn't realize that I could safely open the file for writing, not from the existing FileStream, but by specifying the path. This allowed me to set append to false.

EDIT:

A simpler solution is found in this answer: How to truncate a file in c#?

Just call SetLength(0) before writing.

Troels Larsen
  • 4,462
  • 2
  • 34
  • 54
  • 1
    Please note that you can't share a FileStream between multiple StreamReader/StreamWriter instances. The FileShare.xxx options control how multiple handles/FileStreams can be used against the same file. – David Browne - Microsoft Oct 02 '19 at 20:31
  • @DavidBrowne-Microsoft: Hm.. I had actually expected that to be the case, but I've yet to encounter adverse effects of doing so. What sort of problems should I be seeing as it appears to work fine? And how would I then lock a file for Write elsewhere yet allow my own application to write to it? – Troels Larsen Oct 03 '19 at 21:05
  • 1
    The Readers and Writers have internal buffers, and expect the FileStream location to _not change_ without them knowing about it. The FileStream has only _one_ Location at which the next Read or Write will occur. – David Browne - Microsoft Oct 03 '19 at 21:09
  • @DavidBrowne-Microsoft: Ah thank you very much. The reason I'm not seeing it is because I only use the Reader once. I'll refactor my code just to guard against future changes. – Troels Larsen Oct 04 '19 at 06:28