多线程并发删除日志小工具

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 + "
" + 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 = "任务执行中...";
        }

  这样就实现了多线程之间的并发执行,下面是页面效果图

上面就是我自己这次的总结,只上传了些核心代码,有不对的地方尽请谅解,只是个人的学习记录。

原文地址:https://www.cnblogs.com/suzhiyong1988/p/5211902.html