simultaneous read-write a file in C#

43,676

Solution 1

Ok, two edits later...

This should work. The first time I tried it I think I had forgotten to set FileMode.Append on the oStream.

string test = "foo.txt";

var oStream = new FileStream(test, FileMode.Append, FileAccess.Write, FileShare.Read); 
var iStream = new FileStream(test, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); 

var sw = new System.IO.StreamWriter(oStream);
var sr = new System.IO.StreamReader(iStream); 
var res = sr.ReadLine(); 
res = sr.ReadLine();
sw.WriteLine("g"); 
sw.Flush(); 
res = sr.ReadLine();
res = sr.ReadLine();
sw.WriteLine("h"); sw.Flush();
sw.WriteLine("i"); sw.Flush(); 
sw.WriteLine("j"); sw.Flush(); 
sw.WriteLine("k"); sw.Flush(); 
res = sr.ReadLine(); 
res = sr.ReadLine(); 
res = sr.ReadLine();
res = sr.ReadLine();
res = sr.ReadLine();
res = sr.ReadLine();

Solution 2

@mikerobi is correct, when you write to the stream the file pointer is changed and moved to the end of the stream. What you are not counting on is that StreamReader has its own buffer. It reads 1024 bytes from the file and you'll get results from that buffer. Until the buffer runs out so it has to read from the FileStream again. Finding nothing because the file pointer is at the end of the file.

You really do need to separate FileStreams, each with their own file pointer to have any hope of making this work.

Solution 3

I believe that every time you write a character, you are advancing the stream position, so the next read attempts to read after the character you just wrote. This happens because your stream reader and stream writer are using the same FileStream. Use a different filestream, or seek -1 characters back in the stream after every write.

Solution 4

It's highly unlikely that you'd be happy with any solution to this problem that involves using the same stream for reading and writing. That's especially true if you're trying to read the tail of the file using a StreamReader.

You want to have two different file streams. The writing stream can be a StreamWriter if you like. The reading stream should be a binary stream (i.e. create with File.OpenRead or FileStream.Create), read raw bytes from the file, and convert to text. My answer to this question shows the basics of how it's done.

Share:
43,676
tbischel
Author by

tbischel

Software Engineer working at SendGrid. I got my Masters in Mechanical Engineering, though my focus was Pen Based interfaces for CAD. My undergraduate degree was in Electrical Engineering and Computer Science from UC Berkeley.

Updated on September 29, 2020

Comments

  • tbischel
    tbischel over 3 years

    I have a file containing data that I'd like to monitor changes to, as well as add changes of my own. Think like "Tail -f foo.txt".

    Based on this thread, it looks like I should just create a filestream, and pass it both to a writer and reader. However, when the reader reaches the end of the original file, it fails to see updates I write myself.

    I know it seems like a weird situation... its more an experiment to see if it can be done.

    Here is the example case I tried:


    foo.txt:
    a
    b
    c
    d
    e
    f


            string test = "foo.txt";
            System.IO.FileStream fs = new System.IO.FileStream(test, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite);
    
            var sw = new System.IO.StreamWriter(fs);
            var sr = new System.IO.StreamReader(fs);
    
            var res = sr.ReadLine();
            res = sr.ReadLine();
            sw.WriteLine("g");
            sw.Flush();
            res = sr.ReadLine();
            res = sr.ReadLine();
            sw.WriteLine("h");
            sw.Flush();
            sw.WriteLine("i");
            sw.Flush();
            sw.WriteLine("j");
            sw.Flush();
            sw.WriteLine("k");
            sw.Flush();
            res = sr.ReadLine();
            res = sr.ReadLine();
            res = sr.ReadLine();
            res = sr.ReadLine();
            res = sr.ReadLine();
            res = sr.ReadLine();
    

    After getting past "f", the reader returns null.