1、文件实时写入
最近需要为实验室写一个监控文本数据并实时读取绘制曲线的小程序,原软件从串口接收传感器的数据,实时写入txt文本,现在需要写个程序实时读取出来,遇到一个问题:原软件有个文本框实时显示数据,查看源代码发现文本框显示和写入文本是同时完成的,但是文件写入却有延迟,有时候过去很长时间重新打开文本文件,内容都不发生改变。每次文本容量增加512字节内容才发生变化,这样就导致无法对该文件进行实时读取和监控,找了很多资料,发现这样一段话:
”在PC硬件体系结构里,速度最快的存储器是CPU里面的寄存器,接着到二级缓存,再到系统RAM内存,最后才到硬盘。由于这样的体系结构,就决定了操作系统对文件的操作方式,或者说是最优化的算法。比如操作系统接收到写文件的数据时,就会先把数据保存到RAM里,然后在合适的时间或者合适的数据量时再写到硬盘里。但有时候我们希望数据一定要保存到硬盘里,而不是保存在RAM里,这时就需要使用函数FlushFileBuffers来把RAM里的数据保存到硬盘里。”
于是修改原软件的源代码(VB):
Private Declare Function FlushFileBuffers Lib "kernel32" (ByVal hFile As Long) As Long
'创建文件
strTFile=path//路径
hTFile = FreeFile
Open strTFile For Append As hTFile
'此处为strOut内容写入
Print #hTFile, strTOut
FlushFileBuffers (hTFile)
这样修改后,还是没达到目的。在另一网页上看到一个建议是需要当写入文件完成后需要及时闭。因此在每次打开文件之后增加了如下关闭文件的代码:
Close hTFile '关闭文件
果然文件实现了实时的写入,不过这样性能肯定下降,由于写入频率不快,在可接受范围,就没对性能进行分析。接下来测试下FlushFileBuffers函数有没有发挥作用,删去该函数,发现文件仍然实时写入,因此,文件 open、Print,再Close文件之后,就可以实时将数据写到磁盘的文件系统上,FlushFileBuffers 函数并不能实时写磁盘!
2、文件的实时读取
监控小程序采用C#编写,采用 FileStream和StreamReader实时读取文本文件。采用如下代码:
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
StreamReader sr = new StreamReader(fs, Encoding.Default);
这里出现一个问题,提示:
解决办法是:采用共享读写方式,就没问题
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
StreamReader sr = new StreamReader(fs, Encoding.Default);
3、文件的实时监控
实践中用了两种办法(取一):
(1) 采用timer计时器,每个一定间隔分别对该文件的大小进行计算,当发生改变时,触发事件
private void button3_Click(object sender, EventArgs e)
{
timer1.Interval = 500;
timer1.Enabled = true;
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (foldPath == "" || file == "") return;
FileInfo fi = new FileInfo(foldPath + "//" + file);
fi.Refresh();
Int64 size = fi.Length;
textBox3.Text = size.ToString();//实时显示文件字节数
}
(2)第二中办法是,采用 FileSystemWatcher类,如下:
//监控函数
private void startWatch()
{
if (foldPath == "" || file == "") return;
watch = new FileSystemWatcher();
this.watch.Changed += new FileSystemEventHandler(File_changed);//注册事件
this.watch.Path = @foldPath;//监视的目录
this.watch.Filter = file;//监视的文件
this.watch.IncludeSubdirectories = false;//不监视子目录
this.watch.EnableRaisingEvents = true;//开始监控
}
int sun = 0;
//文件有修改引发的事件
private void File_changed(object sender, FileSystemEventArgs e)
{
if (e.FullPath ==foldPath+"\\"+ file)
{
//监视到文件被修改
sun = sun + 1;//统计改变的次数
}
}
//End
参考文章:1、http://bbs.csdn.net/topics/350041265
2、http://blog.csdn.net/caimouse/article/details/1837984
3、http://blog.csdn.net/wangbaochu/article/details/44305591
4、http://bbs.bccn.net/thread-350527-1-1.html