Подтвердить что ты не робот

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

У меня есть файл, содержащий данные, на которые я хочу отслеживать изменения, а также добавлять собственные изменения. Подумайте, как "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" читатель возвращает null.

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

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

Ответ 4

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

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

Ответ 5

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