3

How can I open a FileStream, read the file contents, and then write (append) to file without re-opening the file?

A problem with StreamReader/StreamWriter in this case is they assume ownwership of the underlying stream. Since the target is .NET 4 the "leaveOpen" constructor overloads cannot be used. (I don't care if StreamReader/StreamWriter are used - but they do provide ReadLine and WriteLine operations.)

In summary, example of problematic code related to the question and how the application will access and manage the lifetime of the FileStream (that is to be opened once):

var fs = File.Open(..);
using (var reader = new StreamReader(fs)) {
   // Do all reading here, then ditch the reader
}  // .. but StreamReader will Close the FileStream

SeekToEnd(fs);

using (var writer = new StreamWriter(fs)) {
   // Do all writing here, then ditch the writer
   // .. ideal, but FileStream already Closed
}

// Finally, somewhere else:
fs.Close();

The "relevant" MSDN articles I have found always show this as two separate steps: this question is about doing the read-then-write operation of Text in a Line-oriented manner without opening the file twice.

The file is opened as

File.Open(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite)

and the underlying stream will always be seek-able and write-able.

Community
  • 1
  • 1
user2864740
  • 60,010
  • 15
  • 145
  • 220
  • Why do you have to close the reader before opening the writer? Why can't you have them both open at the same time? – gunr2171 Feb 25 '15 at 20:48
  • @gunr2171 "Long running application". The first phase is to replay a log, the second phase is to append to the same log.. while I could keep the Reader around indefinitely, such that it is never Closed, I'd really like to find a 'better' way. – user2864740 Feb 25 '15 at 20:51
  • I think the heaviest thing about the stream readers is the actual stream, I don't see the harm with just keeping them both open, the only other way to solve this in your case would be to implement a new stream reader and writer that don't dispose the file stream – konkked Feb 25 '15 at 20:52
  • It's not about "using resources" (there is only one FileStream after all, and the entire buffer used by the reader is inconsequential) - it's about "shaking my head" at using a field just to maintain the reader lifetime (it must be kept GC-alive) and omitting using `using` around the read (which is a local operation, the write will happen many times until the parent is Disposed). – user2864740 Feb 25 '15 at 20:53
  • 1
    @user2864740 I understand that you want to do it that way (because it makes more sense that way) but you would either have to implement it yourself or just keep the variables open, or upgrade to a version of .NET that allows you to use the flag you mentioned to keep the file stream open – konkked Feb 25 '15 at 20:56

1 Answers1

5

You be able to just set the position of the stream to the end of the stream and write from there

 fs.Position = fs.Length;
 //then do the write operations you need to do

Even if you are using a stream writer or reader you should be able to modify the FileStream that the reader/writer is consuming, which would allow you to read then write

using(var fs = File.Open(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite)
{
    using(var reader = new TextReader(fs))
    using(var writer = new TextWriter(fs))
    {
        //read

        fs.Position = fs.Length;

        //write
    }
}
konkked
  • 3,161
  • 14
  • 19
  • FileStream does not offer Text-related operations methods like WriteLine and ReadLine which come from StreamReader/StreamWriter - and when a StreamReader/StreamWriter is Disposed it will (by default) *automatically dispose the underlying stream*. I am limited to .NET 4 so I [cannot use the "leaveOpen" constructor overloads](https://msdn.microsoft.com/en-us/library/gg712952(v=vs.110).aspx). – user2864740 Feb 25 '15 at 20:30
  • @user2864740, updated answer, you should be able to still modify the stream even when it is consumed by a reader, if this is the case just wait until the end to dispose both of the stream handling objects – konkked Feb 25 '15 at 20:44
  • While that update "would work" by effect of not doing the writing *after* the reader is disposed (and the fact the Dispose calls are idempotent), it dodges the question. I don't want to keep around the reader "just so that doesn't Close the source" (it has to be kept GC-alive as well). In this application the reading is done once at the start and the writing over some time, until the application closes (think of it as a log). – user2864740 Feb 25 '15 at 20:44
  • @user2864740: Are you worried that keeping the TextReader undisposed would cause some kind of performance issue? I suspect that the memory cost of keeping a TextReader open is pretty trivial, considering you want the underlying stream to be left open anyway. – StriplingWarrior Feb 25 '15 at 21:10
  • @StriplingWarrior No, I am not worried about "performance" - I go by 97/3. I also go by the 3 (or 6) virtues. See my comment on the main question. – user2864740 Feb 25 '15 at 21:21
  • While I'm *not* fond of "leaving the reader open indefinitely over the writing" this approach does work so.. – user2864740 Mar 04 '15 at 16:56