simultaneous read-write a file in C#

2020-01-23 20:43发布

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.

4条回答
祖国的老花朵
2楼-- · 2020-01-23 21:15

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

查看更多
一纸荒年 Trace。
3楼-- · 2020-01-23 21:19

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();
查看更多
贼婆χ
4楼-- · 2020-01-23 21:28

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.

查看更多
够拽才男人
5楼-- · 2020-01-23 21:40

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.

查看更多
登录 后发表回答