追加行だけ読み出すクラスの実装
定期的に更新(末尾に追記されていく)ログファイルの追記された行だけ読み出したい
前回読み出した値を始点にして読み出す実装
※改行が\rのファイルには未対応(\r\n,\nはいけるはず)。bom付utfだと最初の1行にbomがついてくる
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace WindowsFormsApp1
{
class FileReaderOnlyAdd
{
private string _filePath;
private string _fileEncoding;
private int _nextPos;
public FileReaderOnlyAdd(string filePath, string fileEncoding )
{
this._filePath = filePath;
this._fileEncoding = fileEncoding;
this._nextPos = 0;
}
public string[] GetAddText()
{
string txtAll = null;
string[] txtLines = null;
int endlinepos = 0;
if (File.Exists(this._filePath))
{
using (FileStream fs = new FileStream(this._filePath, FileMode.Open, FileAccess.Read))
{
//追加データあり
if (fs.Length > this._nextPos)
{
using (BinaryReader br = new BinaryReader(fs))
{
//Read済み位置までシーク
fs.Seek(this._nextPos, System.IO.SeekOrigin.Begin);
//Read済み位置から終点まで取り出す
int len = (int)fs.Length - this._nextPos;
var bfr = br.ReadBytes(len);
//出力済みの行(一番後ろの\n)まで取り出す(末行は出力中の可能性がある)
for (int i = bfr.Length - 1; i >= 0; i--)
{
if (bfr[i] == 0x0a)
{
endlinepos = i;
txtAll = System.Text.Encoding.GetEncoding(this._fileEncoding).GetString(bfr, 0, endlinepos + 1);
//末尾の改行を取る(splitすると余計な空要素が出るため)
txtAll = txtAll.TrimEnd('\n');
txtAll = txtAll.TrimEnd('\r');
//改行コードでsplit
txtLines = txtAll.Replace("\r\n", "\n").Split(new[] { '\n', '\r' });
//次の読み出し位置を記憶
this._nextPos += endlinepos + 1;
break;
}
}
}
}
}
}
return txtLines;
}
}
}
実際に使ってみる
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
private FileReaderOnlyAdd fr;
public Form1()
{
InitializeComponent();
fr = new FileReaderOnlyAdd("test.csv", "utf-8");
}
private void button1_Click(object sender, EventArgs e)
{
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
string[] txtLines = fr.GetAddText();
if (txtLines != null)
{
foreach (string txt in txtLines)
{
//Console.WriteLine(txt);
textBox1.AppendText(txt + "\r\n");
}
}
}
}
}
ファイル監視間隔が秒オーダーであれば十分使えそう
msオーダーだと間に合わないかも
コメント