Задать положение StreamReader не работает читать текстовый файл только для добавления - PullRequest
0 голосов
/ 09 мая 2018

У меня есть файл журнала только для добавления, который отслеживается FileSystemWatcher . Когда файл изменяется, для объекта LogFile вызывается Read(). Файл журнала следует читать построчно.

Цель состоит в том, чтобы прочитать только изменения, т. Е. Добавить строки в файл журнала (пропустить уже прочитанные строки). Таким образом, StreamReader должен начать читать с той позиции, где он закончился при предыдущем чтении.

Мое решение пока не работает. Когда я добавляю

1

2

3

4

строка за строкой в ​​Notepad ++ в мой текстовый файл и сохранять каждый раз, когда добавляется строка, вывод отладки:

Initial read
1 //OK
2 //OK
3 //OK
1 //looks like the log file is read again from the beginning
2
3
4

Вывод должен быть

Initial read
1
2
3
4

Есть идеи, как решить эту проблему?

Код консоли

public class LogFile
    {
        public List<string> Contents { get; }
        string _fullPath;
        long position;

        public LogFile(string fullPath)
        {
            if (File.Exists(fullPath))
            {
                _fullPath = fullPath;
                Contents = new List<string>();
                Read();
            }
            else
            {
                throw new FileNotFoundException($"{fullPath} not found");
            }
        }


        public void Read(FileSystemWatcher fsw = null)
        {
            if (fsw != null)
                fsw.EnableRaisingEvents = false; //set to false to prevent Changed event be fired twice

            FileStream fs = null;
            StreamReader sr = null;

            try
            {
                fs = new FileStream(_fullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                try
                {
                    sr = new StreamReader(fs, Encoding.UTF8);
                    if (Contents.Count == 0)
                    {
                        Debug.WriteLine($"Initial read");
                        AddToContents(_fullPath, sr);
                        position = fs.Length; //store the length of the stream
                    }
                    else
                    {
                        sr.DiscardBufferedData();
                        sr.BaseStream.Seek(position, SeekOrigin.Begin);
                        AddToContents(_fullPath, sr);
                        position = fs.Length; //store the length of the stream
                    }

                }
                catch (Exception ex)
                {
                    Debug.WriteLine($"Error while reading from {_fullPath}");
                    //log exception 
                }
                finally
                {
                    if (sr != null)
                        sr.Close();
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"Error while opening {_fullPath}");
                //log exception 
            }
            finally
            {
                if (fs != null)
                    fs.Close();
                if (fsw != null)
                    fsw.EnableRaisingEvents = true; //set raise events for the filesystemwatcher to true 
            }
        }

        private List<string> AddToContents(string fullPath, StreamReader sr)
        {
            List<string> newLines = new List<string>();
            try
            {
                while (!sr.EndOfStream)
                {
                    try
                    {
                        string line = sr.ReadLine();
                        if (line != string.Empty)
                        {
                            Contents.Add(line);
                            newLines.Add(line);
                            Debug.WriteLine(line);
                        }

                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine($"Error processing line in {fullPath}");
                        throw;
                    }
                }
                return newLines;

            }
            catch (Exception ex)
            {
                Debug.WriteLine($"Error while reading from {fullPath}");
                throw;
            }
        }
    }
    class Program
    {
        static LogFile file;
        static FileSystemWatcher fsw;
        static void Main(string[] args)
        {
            string path = @"C:\Temp\test.txt";
            file = new LogFile(path);
            CreateWatcher(path);
            Console.ReadKey();
        }

        private static FileSystemWatcher CreateWatcher(string fileNameFullPath)
        {
            fsw = new FileSystemWatcher(Path.GetDirectoryName(fileNameFullPath)); //constructor only accepts directory path
            fsw.IncludeSubdirectories = false;
            fsw.Filter = Path.GetFileName(fileNameFullPath); //filter for the given file 
            fsw.NotifyFilter = NotifyFilters.LastWrite;
            fsw.EnableRaisingEvents = true;
            fsw.Changed += Fsw_Changed;
            return fsw;
        }

        private static void Fsw_Changed(object sender, FileSystemEventArgs e)
        {
            if (file != null)
                file.Read(fsw);
        }
    }

1 Ответ

0 голосов
/ 09 мая 2018

Проблема

 position = fs.Length; //store the length of the stream

Вы должны хранить текущую позицию потока в поле позиции, а не длину потока, потому что иногда FileStream.Length равен нулю (я не знаю почему)

this.position = fs.Position;

и убедитесь, что FileStream.Length равно нулю, пропустите это изменение

 fs = new FileStream(this._fullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
        if (fs.Length != 0)
        {
            try
            {
                sr = new StreamReader(fs);
                if (this.Contents.Count == 0)
                {
                   ......

Сейчас работает

...