web-dev-qa-db-ja.com

C#でのファイルの同時読み取り/書き込み

変更を監視したり、独自の変更を追加したりするデータを含むファイルがあります。 「Tail-ffoo.txt」のように考えてください。

このスレッド に基づくと、ファイルストリームを作成し、それをライターとリーダーの両方に渡す必要があるようです。ただし、リーダーが元のファイルの最後に到達すると、自分で作成した更新が表示されません。

私はそれが奇妙な状況のように見えることを知っています...それができるかどうかを確かめるための実験です。

これが私が試した例のケースです:


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();

「f」を超えた後、リーダーはnullを返します。

15
tbischel

わかりました、後で2つの編集...

これはうまくいくはずです。初めて試したときは、oStreamでFileMode.Appendを設定するのを忘れていたと思います。

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();
22
MarkPflug

@mikerobiは正しいです。ストリームに書き込むと、ファイルポインターが変更され、ストリームの最後に移動します。あなたが期待していないのは、StreamReaderが独自のバッファを持っているということです。ファイルから1024バイトを読み取り、そのバッファから結果を取得します。バッファがなくなるまで、FileStreamから再度読み取る必要があります。ファイルポインタがファイルの最後にあるため、何も見つかりません。

これを機能させるためには、それぞれ独自のファイルポインタを持つFileStreamを分離する必要があります。

9
Hans Passant

文字を書くたびにストリームの位置が進んでいると思いますので、次の読み取りは今書いた文字の後に読み込もうとします。これは、ストリームリーダーとストリームライターが同じFileStreamを使用しているために発生します。別のファイルストリームを使用するか、書き込みのたびにストリーム内で-1文字をシークします。

3
mikerobi

読み取りと書き込みに同じストリームを使用することを含むこの問題の解決策に満足する可能性はほとんどありません。これは、StreamReaderを使用してファイルの末尾を読み取ろうとしている場合に特に当てはまります。

2つの異なるファイルストリームが必要です。必要に応じて、書き込みストリームをStreamWriterにすることができます。読み取りストリームはバイナリストリームである必要があり(つまり、File.OpenReadまたはFileStream.Createで作成)、ファイルから生のバイトを読み取り、テキストに変換します。 この質問 に対する私の答えは、それがどのように行われるかの基本を示しています。

2
Jim Mischel

StreamReader.DiscardBufferedData()の呼び出しを追加すると、動作は変わりますか?

1
Mike Morearty