使用 FileSystemWatcher 监控文件资源管理器特定文件新增、编辑、删除。因文件修改一次会引起多次回调和通知,为确保对文件处理时文件已经编辑完成,使用files 对象保存变更文件的记录,每个文件只保留一条数据,并且记录最后一次文件操作的时间。使用定时器每间隔固定时间检查几分钟之前变更的文件进行操作。
使用到的全局参数
#region 配置文件中数据参数获取
/// <summary>
/// 文件监控路径,文件输入路径
/// </summary>
string FilePath = System.Configuration.ConfigurationSettings.AppSettings["FilePath"].ToString();
/// <summary>
/// 转换成功后的输出路径
/// </summary>
string OutPutPath = System.Configuration.ConfigurationSettings.AppSettings["OutPutPath"].ToString();
/// <summary>
/// 计时器执行间隔时间,多长时间检查一次变动结束的数据
/// </summary>
string TimeoutMillis = System.Configuration.ConfigurationSettings.AppSettings["TimeoutMillis"].ToString();
/// <summary>
/// 数据变更结束后等待的时间,单位秒,例如ChangedTime = 60,代表最后一次触发时间距离现在1分钟
/// </summary>
string ChangedTime = System.Configuration.ConfigurationSettings.AppSettings["ChangedTime"].ToString();
#endregion
#region 全局变量
//异步更新UI信息
System.IO.FileSystemWatcher watcherJson = null;//磁盘监控类,监控风轨迹和图谱
System.IO.FileSystemWatcher watcherVtk = null;//磁盘监控类,监控风廓线和云切片
string fileTypeJson = "*.json";
string fileTypeVtk = "*.txt";
#endregion
/// <summary>
/// 计时器处理回调
/// </summary>
System.Threading.Timer m_timer = null;
/// <summary>
/// 计时器处理事件的锁
/// </summary>
object timeLock = new object();
/// <summary>
/// 用于接受FileSystemWatcher返回的变更的信息
/// </summary>
List<ChangeInfo> files = new List<ChangeInfo>();
/// <summary>
/// 存储需要转换的文件,每隔固定时间(TimeoutMillis)进行循环
/// </summary>
List<ChangeInfo> backup = new List<ChangeInfo>();
文件监控逻辑
/// <summary>
/// 启动文件监控任务
/// </summary>
/// <param name="filetype"></param>
private void FileWatcher(string filetype)
{
if (watcherJson == null && filetype == fileTypeJson)
{
watcherJson = new System.IO.FileSystemWatcher();
watcherJson.Path = FilePath;
watcherJson.Filter = fileTypeJson;
watcherJson.Changed += new System.IO.FileSystemEventHandler(OnProcessChanged);
watcherJson.Created += new System.IO.FileSystemEventHandler(OnProcessChanged);
watcherJson.Deleted += new System.IO.FileSystemEventHandler(OnProcessChanged);
watcherJson.Renamed += new System.IO.RenamedEventHandler(OnProcessChanged);
watcherJson.IncludeSubdirectories = true;
watcherJson.InternalBufferSize = 65536;
watcherJson.EnableRaisingEvents = true;
watcherJson.NotifyFilter = System.IO.NotifyFilters.FileName | //文件名
System.IO.NotifyFilters.DirectoryName | // 目录名
System.IO.NotifyFilters.Size // 文件或文件夹的大小
| System.IO.NotifyFilters.Attributes | // 文件或文件夹的特性
System.IO.NotifyFilters.LastWrite | // 上一次向文件或文件夹写入内容的日期
System.IO.NotifyFilters.LastAccess | // 文件或文件夹上一次打开的日期
System.IO.NotifyFilters.CreationTime | // 文件或文件夹的创建时间
System.IO.NotifyFilters.Security; // 文件或文件夹的安全设置
}
if (watcherVtk == null && filetype == fileTypeVtk)//*.vtk
{
watcherVtk = new System.IO.FileSystemWatcher();
watcherVtk.Path = FilePath;
watcherVtk.Filter = fileTypeVtk;
watcherVtk.Changed += new System.IO.FileSystemEventHandler(OnProcessChanged);
watcherVtk.Created += new System.IO.FileSystemEventHandler(OnProcessChanged);
watcherVtk.Deleted += new System.IO.FileSystemEventHandler(OnProcessChanged);
watcherVtk.Renamed += new System.IO.RenamedEventHandler(OnProcessChanged);
watcherVtk.IncludeSubdirectories = true;
watcherVtk.InternalBufferSize = 65536;
watcherVtk.EnableRaisingEvents = true;
watcherVtk.NotifyFilter = System.IO.NotifyFilters.FileName | //文件名
System.IO.NotifyFilters.DirectoryName | // 目录名
System.IO.NotifyFilters.Size // 文件或文件夹的大小
| System.IO.NotifyFilters.Attributes | // 文件或文件夹的特性
System.IO.NotifyFilters.LastWrite | // 上一次向文件或文件夹写入内容的日期
System.IO.NotifyFilters.LastAccess | // 文件或文件夹上一次打开的日期
System.IO.NotifyFilters.CreationTime | // 文件或文件夹的创建时间
System.IO.NotifyFilters.Security; // 文件或文件夹的安全设置
}
if (m_timer == null && (watcherJson != null || watcherVtk != null))
{
int sss = 20000;
sss = int.TryParse(TimeoutMillis, out sss) ? sss : 20000;
//设置定时器的回调函数。此时定时器未启动
m_timer = new System.Threading.Timer(new System.Threading.TimerCallback(OnWatchedFileChange), this, 0, sss);
}
}
void OnProcessChanged(object sender, System.IO.FileSystemEventArgs e)
{
//获取文件变更的类型
var changtype = GetChangeType(e.ChangeType);
System.Threading.Mutex mutex = new System.Threading.Mutex(false, "FSW");
mutex.WaitOne();
ChangeInfo info = new ChangeInfo();
info.Name = e.Name;
info.FullPath = e.FullPath;
if (e.ChangeType != System.IO.WatcherChangeTypes.Deleted)
{
bool IsExists = false;//当前文件是否在变更集合中
for (int i = 0; i < files.Count; i++)
{
if (files[i].Name == info.Name && files[i].FullPath == info.FullPath)
{
IsExists = true;
files[i].LastTime = DateTime.Now;
break;
}
}
if (!IsExists)
{
info.LastTime = DateTime.Now;
files.Add(info);
LogHelper.GetInstance().Info(string.Format("OnProcessChanged 文件【{0}】加入待处理队列", e.FullPath));
}
}
else
{
files = files.Where(aa => aa.Name != info.Name && aa.FullPath != info.FullPath).ToList();
LogHelper.GetInstance().Info(string.Format("OnProcessChanged 文件【被删除】名称【{0}】路径{1}", e.Name, e.FullPath));
}
mutex.ReleaseMutex();
}
通过计时器处理文件转移
private void OnWatchedFileChange(object state)
{
lock (timeLock)
{
int ss = 120;
ss = int.TryParse(ChangedTime, out ss) ? ss : 120;
var tempList = files.Where(aa => (DateTime.Now - aa.LastTime).TotalSeconds > ss).ToList();
backup.AddRange(tempList);
for (int i = 0; i < tempList.Count(); i++)
{
files.Remove(tempList[i]);
}
LogHelper.GetInstance().Debug(string.Format("变更文件待处理数量【{0}】即将处理数量【{1}】!", files.Count, backup.Count));
if (backup.Count > 0)
{
//输出obj路径
if (!OutPutPath.Last<char>().Equals('\\'))
{
OutPutPath = OutPutPath + "\\";
}
string newfilename = "";//对文件进行重命名
string filePathOnly = "";//D:\Temp
string folderName = "";//当前文件对应的父级文件夹
string copypath = "";//输出的目标路径
List<int> arry = new List<int>();
int index = 0;
foreach (ChangeInfo file in backup)
{
try
{
newfilename = file.Name.Replace("\\", "_");//对文件重命名
filePathOnly = System.IO.Path.GetDirectoryName(file.FullPath); //D:\Temp
folderName = System.IO.Path.GetFileName(filePathOnly);//当前文件对应的父级文件夹
copypath = OutPutPath + folderName + "\\" + newfilename.Substring(0, newfilename.LastIndexOf('.'))+"\\";
if (!System.IO.Directory.Exists(copypath))
{
//创建输出目录
System.IO.Directory.CreateDirectory(copypath);
}
if (System.IO.File.Exists(file.FullPath))
{
//复制原始数据文件
System.IO.File.Copy(file.FullPath, copypath + newfilename, true);
LogHelper.GetInstance().Debug(string.Format("路径【{0}】已复制到【{1}】重命名为【{2}】", file.FullPath, copypath, newfilename));
}
else {
LogHelper.GetInstance().Debug(string.Format("文件【{0}】不存在", file.FullPath, copypath, newfilename));
}
arry.Add(index);
index++;
}
catch (Exception ex)
{
LogHelper.GetInstance().Debug(string.Format("路径【{0}】复制失败:{1}",file.FullPath, ex.Message));
}
}
for (int i = arry.Count; i > 0; i--)
{
backup.Remove(backup[i - 1]);
}
LogHelper.GetInstance().Debug(string.Format("变更文件待处理数量【{0}】剩余处理数量【{1}】本次处理【{2}】!", files.Count, backup.Count, arry.Count));
}
}
}
根据变更的参数获取变更描述
private string GetChangeType(System.IO.WatcherChangeTypes watcherChangeTypes)
{
string str = "";
switch (watcherChangeTypes)
{
case System.IO.WatcherChangeTypes.Created:
str = "新建";
break;
case System.IO.WatcherChangeTypes.Deleted:
str = "删除";
break;
case System.IO.WatcherChangeTypes.Changed:
str = "更改";
break;
case System.IO.WatcherChangeTypes.Renamed:
str = "重命名";
break;
case System.IO.WatcherChangeTypes.All:
str = "创建、删除、更改或重命名";
break;
default:
str = "未知状态";
break;
}
return str;
}
变更文件对象
public class ChangeInfo
{
public string Name { get; set; }
public string FullPath { get; set; }
public DateTime LastTime { get; set; }
}
程序调用方法
FileWatcher(fileTypeJson);
FileWatcher(fileTypeVtk);
另外,如果在程序关闭期间文件变更,则无法知晓。可通过记录程序退出时间,对退出后修改的文件进行筛选。