simultaneous read-write a file in C#
Asked Answered
T

4

16

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.

Tengdin answered 28/9, 2010 at 22:28 Comment(2)
A poster did put something up about having two file streams pointing to the same object... that did work. Even if the reader reaches the end of the file, if the writer updates, the reader stream gets both results.Tengdin
Yeah, that was me deleting my post after it didn't work like I expected it to. I undeleted it with an explanation of why...Ramulose
R
25

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();
Ramulose answered 28/9, 2010 at 22:37 Comment(1)
I chnaged the oStream's FileShare.ReadWrite .Metathesis
B
10

@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.

Beagle answered 28/9, 2010 at 23:10 Comment(1)
Thanks Hans, I was looking to confirm this fact in trying to develop a solution myself. It was helpful to see that I seem to be coming to the same conclusion.Haldi
B
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.

Bauer answered 28/9, 2010 at 22:35 Comment(1)
well the way I interleave the writes and reads was to see if this was the case. The reader still reads correctly in order, it just doesn't see any new data added by the writer.Tengdin
S
2

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.

Sylvester answered 28/9, 2010 at 23:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.