/// <summary> /// 清除空目录 /// </summary> /// <param name="topDir">顶级目录</param> /// <param name="currentDepth">当前递归深度</param> /// <returns>删除目录的个数</returns> private int CleanEmptyDirectory(string topDir, int currentDepth) { if (currentDepth > MaxRecursiveDepth) { NLogHelper.Warn("日志文件夹存在快捷方式导致无穷递归"); return(0); } DirectoryInfo dirInfo = new DirectoryInfo(topDir); if (!dirInfo.Exists) { NLogHelper.Warn($"未找到{topDir}目录,无法清理"); return(0); } //递归子文件夹 DirectoryInfo[] subDirs = dirInfo.GetDirectories();//返回当前目录的子目录。如果没有子目录,则此方法返回一个空数组。 此方法不是递归的。 //非空子目录集合 List <DirectoryInfo> nonEmptyDirList = new List <DirectoryInfo>(); DateTime now = DateTime.Now; //删除目录的个数 int delCount = 0; //删除空目录 foreach (var currentDir in subDirs) { //获取存在子目录的目录 if (currentDir.Exists && currentDir.GetDirectories().Length != 0) { nonEmptyDirList.Add(currentDir); } else if (currentDir.Exists && currentDir.GetFileSystemInfos().Length == 0 && (now - currentDir.CreationTime).TotalDays > 7) { // 删除放在后面 //文件夹为空, 并且空目录至少3天没有使用 try { currentDir.Delete(); delCount++; NLogHelper.Trace("删除空目录:" + currentDir.FullName); } catch (Exception ex) { NLogHelper.Warn($"删除空目录{currentDir.FullName}失败:{ex}"); } } } //递归子目录 foreach (var subDir in nonEmptyDirList) { delCount += CleanEmptyDirectory(subDir.FullName, currentDepth + 1); } return(delCount); }
/// <summary> /// 清理文件及空目录 /// </summary> /// <param name="topDir">清理的顶层目录,该目录不会被删除</param> /// <param name="fileSearchPatternArr"> /// 文件搜索模式 *所有文件 *.*有拓展名的文件 /// *:表示0个或多个字符 /// ?:表示0个或1个字符 /// 采用*.log|*.txt格式,多个项通过|隔开,该功能是通过自己写代码实现的 /// </param> /// <param name="expireTime">文件过期时间</param> /// <param name="currentDepth">当前递归深度</param> /// <returns>返回删除文件的个数</returns> private int CleanFiles(string topDir, string[] fileSearchPatternArr, DateTime expireTime, int currentDepth) { if (currentDepth > MaxRecursiveDepth) { //目录的快捷方式会被认为是一个文件 NLogHelper.Warn("日志文件夹深度太大或者存在快捷方式导致无穷递归"); return(0); } DirectoryInfo dirInfo = new DirectoryInfo(topDir); if (!dirInfo.Exists) { NLogHelper.Warn($"未找到{topDir}目录,无法清理"); return(0); } //If you choose AllDirectories and the directory structure contains a link that creates a loop, the search operation enters an infinite loop. //FileInfo[] fileInfos = dirInfo.GetFiles(fileSearchPattern, SearchOption.AllDirectories); HashSet <string> fileInfos = new HashSet <string>(); foreach (string searchPatternItem in fileSearchPatternArr) { //仅搜索当前目录,不递归 dirInfo.GetFiles(searchPatternItem, SearchOption.TopDirectoryOnly).Select(r => r.FullName).ToList().ForEach(r => fileInfos.Add(r.Trim())); } //删除文件的个数 int delCount = 0; //删除过期文件 foreach (string fileName in fileInfos) { try { FileInfo fileInfo = new FileInfo(fileName); //文件过期 if (fileInfo.Exists && fileInfo.LastWriteTime < expireTime) { fileInfo.Delete(); delCount++; NLogHelper.Trace("成功删除文件:" + fileInfo.FullName); } } catch (Exception ex) { NLogHelper.Warn($"删除文件{fileName}失败:{ex}"); } } //递归子文件夹 DirectoryInfo[] subDirs = dirInfo.GetDirectories();//返回当前目录的子目录。如果没有子目录,则此方法返回一个空数组。 此方法不是递归的。 foreach (var subDir in subDirs) { delCount += CleanFiles(subDir.FullName, fileSearchPatternArr, expireTime, currentDepth + 1); } return(delCount); }
/// <summary> /// 构造函数 构造完即开启处理线程 /// </summary> /// <param name="singleDataHandler">单个数据处理</param> /// <param name="dataListHandler">如果数据较多,列表处理,如果为null,则不启用列表处理</param> /// <param name="exceptionHandler">数据处理异常后的处理</param> /// <param name="maxNumberDataInQueue">队列中消息的最大数量,超过该数量,之前的消息将被丢弃 最小是100,如果小于100,将会赋值为100</param> /// <param name="isNeedOptimize">是否需要多线程优化消息处理,通常不需要,使用优化是非常危险的行为</param> /// <param name="maxBatchSize">最大允许的单次处理批次数量</param> public BlockingQueueEx(Action <T> singleDataHandler = null, Action <List <T> > dataListHandler = null, Action <Exception> exceptionHandler = null, int maxNumberDataInQueue = 4096, bool isNeedOptimize = false, int maxBatchSize = 29) { lock (_locker) { this._isRunning = true; this._singleDataHandler = singleDataHandler; this._exceptionHandler = exceptionHandler; this._isNeedOptimize = isNeedOptimize; this._dataListHandler = dataListHandler; //列表处理函数不为null,启用列表处理 this._enableListHandler = dataListHandler != null; this._maxBatchSize = maxBatchSize > ThresholdCanBeListHandled?maxBatchSize:ThresholdCanBeListHandled; //队列中消息的最大数量,超过该数量,之前的消息将被丢弃 最小是100,如果小于100,将会赋值为100 if (maxNumberDataInQueue < 100) { this._maxNumDataInQueue = 100; } else { this._maxNumDataInQueue = maxNumberDataInQueue; } } _thread = new Thread(() => { T item = null; Action <T> dataHandlerInThread = null;//单条消息处理 Action <Exception> exceptionHandlerInThread = null; Action <List <T> > dataListHandlerInThread = null; bool enableListHandlerInThread = false; int maxBatchSizeInThread = ThresholdCanBeListHandled; bool isNeedOptimizeInThread = false;//是否需要多线程优化处理,一般不需要 lock (_locker) { dataHandlerInThread = this._singleDataHandler; exceptionHandlerInThread = this._exceptionHandler; dataListHandlerInThread = this._dataListHandler; enableListHandlerInThread = this._enableListHandler; maxBatchSizeInThread = this._maxBatchSize; isNeedOptimizeInThread = this._isNeedOptimize; } while (_isRunning) { try { #region 数据处理 if (enableListHandlerInThread) { //当前队列数据量 int currentCount = _blockingQueue.Count; if (currentCount < ThresholdCanBeListHandled) { #region 单个处理 不需要list处理 if (_blockingQueue.TryTake(out item, 419)) { if (isNeedOptimizeInThread) { //需要优化性能 T tempItem = item; Task.Factory.StartNew(() => { try { dataHandlerInThread?.Invoke(tempItem); } catch (Exception ex) { exceptionHandlerInThread?.Invoke(ex); } }); } else { try { dataHandlerInThread?.Invoke(item); } catch (Exception ex) { exceptionHandlerInThread?.Invoke(ex); } } } #endregion } else { #region 数据较多,列表处理 //单次处理的数据量 int dataListSize = ThresholdCanBeListHandled; if (currentCount > ThresholdCanBeListHandled * 2) { dataListSize = ThresholdCanBeListHandled * 2; } //最大单次处理的批次 if (currentCount > maxBatchSizeInThread) { dataListSize = maxBatchSizeInThread; } List <T> dataList = new List <T>(); for (int i = 0; i < dataListSize; i++) { if (_blockingQueue.TryTake(out item, 111)) { //有数据立刻返回 dataList.Add(item); } else { break; } } if (isNeedOptimizeInThread) { //需要优化性能 Task.Factory.StartNew(() => { try { dataListHandlerInThread?.Invoke(dataList); } catch (Exception ex) { exceptionHandlerInThread?.Invoke(ex); } }); } else { try { dataListHandlerInThread?.Invoke(dataList); } catch (Exception ex) { exceptionHandlerInThread?.Invoke(ex); } } #endregion } } else { #region 单个处理 不需要list处理 if (_blockingQueue.TryTake(out item, 419)) { if (isNeedOptimizeInThread) { //需要优化性能 T tempItem = item; Task.Factory.StartNew(() => { try { dataHandlerInThread?.Invoke(tempItem); } catch (Exception ex) { exceptionHandlerInThread?.Invoke(ex); } }); } else { try { dataHandlerInThread?.Invoke(item); } catch (Exception ex) { exceptionHandlerInThread?.Invoke(ex); } } } #endregion } #endregion } catch (Exception ex) { exceptionHandlerInThread?.Invoke(ex); } } NLogHelper.Trace($"Message处理循环退出"); }); //后台线程 _thread.IsBackground = true; _thread.Priority = ThreadPriority.Normal; _thread.Start(); }
/// <summary> /// 从网络获取时间 /// </summary> /// <param name="url"></param> /// <param name="exceptionHandler"></param> /// <returns></returns> public static DateTime?GetNetworkDateTime(string url, Action <Exception> exceptionHandler = null) { if (string.IsNullOrWhiteSpace(url)) { return(null); } NLogHelper.Trace(url); HttpWebRequest request = null; WebResponse response = null; try { request = (HttpWebRequest)WebRequest.Create(url); request.Timeout = 6000;//单位毫秒 request.Credentials = CredentialCache.DefaultCredentials; request.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore); response = request.GetResponse(); var headers = response.Headers; string dateStr = null; foreach (var item in headers.AllKeys) { if (item == "Date") { //Http响应的Date dateStr = headers[item]; break; } } if (!string.IsNullOrWhiteSpace(dateStr)) { //Convert将尽量尝试解析 return(Convert.ToDateTime(dateStr)); } return(null); } catch (Exception e) { exceptionHandler?.Invoke(e); return(null); } finally { if (request != null) { try { request.Abort(); } catch { } } if (response != null) { try { response.Close(); } catch { } } } }
/// <summary> /// MQ回调 /// </summary> /// <param name="state"></param> private static void MqTimerCallBack(object state) { lock (Slocker) { if (_isRunning) { return; } _isRunning = true; } try { if (!LongRunRabbitConsumer.IsAlive()) { Thread.Sleep(5500); //延迟,使其能够自动恢复 if (!LongRunRabbitConsumer.IsAlive()) { if (_isFirstTimeToStartMq) { _isFirstTimeToStartMq = false; NLogHelper.Debug("首次尝试启动MQConsumer"); LongRunRabbitConsumer.StartConsumer(ex => { NLogHelper.Error($"开启MQ失败:{ex}"); }); } else { _restartCount++; if (_restartCount > 10000000) { _restartCount = 10000; } NLogHelper.Warn($"MQ异常,第{_restartCount}次尝试重启 MQConsumer"); LongRunRabbitConsumer.StartConsumer(ex => { NLogHelper.Error($"开启MQ失败:{ex}"); }); } } } else { NLogHelper.Trace("检测MQ连接正常"); } } catch (Exception ex) { NLogHelper.Error("MQ定时器异常:" + ex); } finally { lock (Slocker) { _isRunning = false; } } }