2016年过年后没什么新任务,于是自己做了个定时删除日志的小工具,方便以后的工作中用到,也希望能给大家一点帮助,有不对的地方多多指教。
功能不是很复杂,主要实现了以下几个功能:
1.定时检测本地磁盘空间,当空间不足时,做出相应的提醒。
2.支持动态创建N个磁盘定时删除任务。
3.支持多线程并发删除操作,避免出现锁死现象。
4.能够同时支持文件的删除和子文件夹的删除。
废话不多说,先上具体代码:
- 删除文件夹里的文件方法
private bool ToDeleteFile(string url)
{
ListViewItem listItem = null;
if (string.IsNullOrWhiteSpace(url))
return false;
else
{
//遍历文件夹里的所有文件
try
{
fileCount = 0;
DirectoryInfo info = new DirectoryInfo(url);
foreach (FileInfo file in info.GetFiles())
{
DateTime lastDate = file.LastWriteTime;//获取文件最后一次写入时间
DateTime dtNow = DateTime.Now;
TimeSpan ts = dtNow - lastDate;
if (sysTie.Enabled == true)
{
if (ts.Days > int.Parse(DeleteLogDays))
{
fileSize += (float.Parse(file.Length.ToString()) / (1024 * 1024));
file.Delete();
fileCount++;
}
}
}
listItem = AddListViewData("成功!--删除文件", "删除" + url + "里的日志文件" + fileCount + "个", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
listItem.ForeColor = Color.Blue;
if (fileCount > 0)
{
this.lstMessage.Items.Add(listItem);
lbl.Text = fileSize.ToString("F2") + " M";
}
return true;
}
catch
{
return false;
}
}
}
- 删除文件夹里的子文件夹方法
private bool ToDeleteFolder(string url)
{
ListViewItem listItem = null;
if (string.IsNullOrWhiteSpace(url))
return false;
else
{
//遍历文件夹里的所有子文件夹
try
{
fileCount = 0;
DirectoryInfo info = new DirectoryInfo(url);
foreach (DirectoryInfo floder in info.GetDirectories())
{
DateTime lastDate = floder.LastWriteTime;//获取文件最后一次写入时间
DateTime dtNow = DateTime.Now;
TimeSpan ts = dtNow - lastDate;
if (sysTie.Enabled == true)
{
if (ts.Days > int.Parse(DeleteFolderDays))
{
fileSize += (float.Parse(GetFloderFileSize(floder.GetFiles()).ToString()) / (1024 * 1024));
floder.Delete(true);
fileCount++;
}
}
}
listItem = AddListViewData("成功!--删除子文件夹", "删除" + url + "里的子文件夹" + fileCount + "个", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
listItem.ForeColor = Color.Blue;
if (fileCount > 0)
{
this.lstMessage.Items.Add(listItem);
lbl.Text = fileSize.ToString("F2") + " M";
}
return true;
}
catch
{
return false;
}
}
}
下面是定时删除任务:
- 定时删除文件夹里的文件
private void StartUpTimerFile(string url)
{
ListViewItem listItem = null;
if (!IsUrlExist(url))
{
listItem = AddListViewData("失败!--启动删除文件", "启动" + url + "路径失败,没有找到对应的文件夹", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
listItem.ForeColor = Color.Red;
}
else
listItem = AddListViewData("成功!--启动删除文件", "启动删除文件任务成功,已开始运行,路径:" + url, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
this.lstMessage.Items.Add(listItem);
sysTie = new System.Timers.Timer(int.Parse(logTime));
sysTie.Elapsed += (o, s) =>
{
if (DateTime.Now.Hour == int.Parse(deleteLogTime))
{
DelegateToDeleteFile del = new DelegateToDeleteFile(ToDeleteFile);
BeginInvoke(del, url);
}
};
sysTie.Start();
}
- 定时删除文件夹里的子文件夹
private void StartUpTimerFolder(string url)
{
ListViewItem listItem = null;
if (!IsUrlExist(url))
{
listItem = AddListViewData("失败!--启动删除子文件夹", "启动" + url + "路径失败,没有找到对应的文件夹", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
listItem.ForeColor = Color.Red;
}
else
listItem = AddListViewData("成功!--启动删除子文件夹", "启动删除子文件夹任务成功,已开始运行,路径:" + url, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
this.lstMessage.Items.Add(listItem);
sysTie = new System.Timers.Timer(int.Parse(FolderTime));
sysTie.Elapsed += (o, s) =>
{
if (DateTime.Now.Hour == int.Parse(DeleteFolderTime))
{
DelegateToDeleteFile del = new DelegateToDeleteFile(ToDeleteFolder);
BeginInvoke(del, url);
}
};
sysTie.Start();
}
由于调用方法时,会报异常,所以这块我采用委托来加载上面的方法:
/// <summary>
/// 委托开始方法--删除文件
/// </summary>
/// <param name="url"></param>
public void DelegateMethodFile(string url)
{
MyDelegateTimer delTimer = new MyDelegateTimer(StartUpTimerFile);
BeginInvoke(delTimer, url);
}
/// <summary>
/// 委托开始方法--删除子文件夹
/// </summary>
/// <param name="url"></param>
public void DelegateMethodFolder(string url)
{
MyDelegateTimer delTimer = new MyDelegateTimer(StartUpTimerFolder);
BeginInvoke(delTimer, url);
}
以上代码单个删除任务的执行,如何实现多个删除任务的并发运行,因为在我写的时候出现了如果我启动多个删除任务的时候stop()上一个运行的任务,只会运行刚刚启动的任务,所以这块我使用了一个高效的线程安全队列ConcurrentQueue,坚持先进先出的原则。
- 创建一个可以由多个线程同时访问的键值集合ConcurrentDictionary<string, string>
public ConcurrentDictionary<string, string> WriteQueue(string s, string prefix)
{
if (string.IsNullOrWhiteSpace(s))
return null;
string val = s;
string key = prefix;
_logQueue.Enqueue(new KeyValuePair<string, string>(key, val));
var dic = GetLogText();
return dic;
}
/// <summary>
/// 写入队列操作
/// </summary>
/// <returns></returns>
private ConcurrentDictionary<string, string> GetLogText()
{
do
{
KeyValuePair<string, string> kv;
if (_logQueue.TryDequeue(out kv))
{
dict.AddOrUpdate(kv.Key, kv.Value, (k, v) => string.Concat(v + "\r\n" + kv.Value));
}
}
while (_logQueue.Count > 0);
return dict;
}
下面是启动多线程事件:
private void button1_Click(object sender, EventArgs e)
{
this.lstMessage.Items.Clear();
dict = new ConcurrentDictionary<string, string>();
_logQueue = new ConcurrentQueue<KeyValuePair<string, string>>();
if (strBackList == null || strBackList.Count == 0)
{
MessageBox.Show("路径不能为空,请输入详细地址!");
return;
}
foreach (KeyValuePair<string, string> obj in strBackList)
{
if (!string.IsNullOrWhiteSpace(obj.Value))
{
string strKey = obj.Key;
string[] s = obj.Value.Split('|');
if (s.Length > 0)
{
foreach (var v in s)
{
if (!string.IsNullOrWhiteSpace(v))
{
dict = WriteQueue(v, string.Format("{0}-{1}", strKey.Substring(0, 1), clickCount.ToString()));
clickCount++;
}
}
}
}
}
if (dict != null)
{
lock (_lockObject)
{
foreach (var kv in dict)
{
if (!string.IsNullOrWhiteSpace(kv.Key))
{
switch (int.Parse(kv.Key.Substring(0, 1)))
{
//All
case 0:
DelegateMethodFile(kv.Value);
DelegateMethodFolder(kv.Value);
break;
case 1://file
DelegateMethodFile(kv.Value);
break;
case 2://folder
DelegateMethodFolder(kv.Value);
break;
default://none
break;
}
}
}
}
}
this.button1.Enabled = false;
button1.Text = "任务执行中...";
}
这样就实现了多线程之间的并发执行,下面是页面效果图
上面就是我自己这次的总结,只上传了些核心代码,有不对的地方尽请谅解,只是个人的学习记录。