Одновременное чтение и запись файла в C#

У меня есть файл, содержащий данные, к которым я хотел бы отслеживать изменения, а также добавлять свои собственные изменения. Думайте как "Tail -f foo.txt".

Исходя из этого потока, похоже, что я должен просто создать файловый поток и передать его как автору, так и читателю. Однако, когда читатель достигает конца исходного файла, он не видит обновления, которые я пишу сам.

Я знаю, это кажется странной ситуацией... это скорее эксперимент, чтобы увидеть, можно ли это сделать.

Вот пример, который я пробовал:


foo.txt:

б
с
d
е
е


        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" читатель возвращает ноль.

5 ответов

Решение

Хорошо, два изменения позже...

Это должно работать. В первый раз, когда я попробовал это, я думаю, что забыл установить FileMode.Append на 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();

@mikerobi правильно, когда вы пишете в поток, указатель файла изменяется и перемещается в конец потока. На что вы не рассчитываете, так это на то, что StreamReader имеет свой собственный буфер. Он читает 1024 байта из файла, и вы получите результаты из этого буфера. Пока буфер не исчерпан, он должен снова читать из FileStream. Ничего не найдено, потому что указатель файла находится в конце файла.

Вам действительно нужно разделить FileStreams, каждый со своим указателем файла, чтобы иметь хоть какую-то надежду на выполнение этой работы.

Я считаю, что каждый раз, когда вы пишете символ, вы продвигаете позицию потока, поэтому следующее чтение пытается прочитать после символа, который вы только что написали. Это происходит потому, что ваш потоковый читатель и потоковый писатель используют один и тот же FileStream. Используйте другой файловый поток или ищите -1 символ обратно в потоке после каждой записи.

Маловероятно, что вы будете довольны любым решением этой проблемы, которое предполагает использование одного и того же потока для чтения и записи. Это особенно верно, если вы пытаетесь прочитать хвост файла, используя StreamReader,

Вы хотите иметь два разных файловых потока. Поток записи может быть StreamWriter если хочешь. Поток чтения должен быть двоичным потоком (т.е. создавать с File.OpenRead или же FileStream.Create), читать необработанные байты из файла и преобразовывать в текст. Мой ответ на этот вопрос показывает основы того, как это делается.

Если вы добавите звонок в StreamReader.DiscardBufferedData(), это меняет поведение?

Другие вопросы по тегам