У меня есть файл журнала только для добавления, который отслеживается 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);
}
}