開發接口程序時,要保證程序穩定運行就要時刻監控接口程序發送和接收的數據,這就需要一個日志記錄的類將需要的信息記錄在日志文件中,便於自己維護接口程序。(Web系統也是如此,只是對應的日志實現比這個要復雜一點)。
剛開始考慮的比較少,沒有加入控制日志文件數量的功能。運行了一段時間,文件夾內的Log文件如下所示:
using System; using System.Collections; using System.IO; namespace DotNetCommon.Logger { /// <summary> /// 實現IComparer接口,實現文件按名稱降序排序 /// </summary> class FileSorter:IComparer { /// <summary> /// 繼承IComparer接口必須實現的方法 /// </summary> /// <param name="x">FileInfo文件x</param> /// <param name="y">FileInfo文件y</param> /// <returns></returns> public int Compare(object x, object y) { if (x == null && y == null) return 0; if (x == null) return -1; if (y == null) return 1; var xInfo = (FileInfo) x; var yInfo = (FileInfo) y; //按名稱降序排序 return String.Compare(yInfo.FullName, xInfo.FullName, StringComparison.Ordinal); } } }
接下來就是實現日志文件自動刪除。具體思路是,當創建一個新的日志文件時,檢測是否超出最大日志允許數量。若超出,使用上面定義的比較器刪除之。日志自動刪除代碼方法如下:
/// <summary> /// 刪除Log目錄多余的日志文件 /// </summary> public void DeleteUnnecessaryLogFiles() { var path = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory + @"Log\"); var fileInfos = path.GetFiles("*.log"); Array.Sort(fileInfos, new FileSorter()); if (fileInfos.Length <= (_maxLogNum - 1)) return; for (var i = _maxLogNum - 1; i < fileInfos.Length; i++) { var filepath = fileInfos[i].FullName; if (!File.Exists(filepath)) continue; try { File.Delete(filepath); } catch (Exception) { return; } } }
Log日志類具體代碼如下所示:
using System; using System.IO; using System.Text; namespace DotNetCommon.Logger { /// <summary> /// 類說明:日志記錄(文本記錄和byte數組記錄) /// 編碼人:鞠小軍 /// 聯系方式:[email protected] /// </summary> class Log { /// <summary> /// 程序當前目錄 /// </summary> private readonly DirectoryInfo _dir = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory); /// <summary> /// 默認日志文件最大數量為20 /// </summary> private readonly int _maxLogNum = 20; /// <summary> /// 構造函數 /// </summary> /// <param name="maxLogNum">Log目錄下日志文件的最大數量</param> public Log(int maxLogNum) { _maxLogNum = maxLogNum; } /// <summary> /// 字符串寫入日志文件 /// </summary> /// <param name="msg">寫入的字符串文本</param> public void WriteLog_Txt(string msg) { FileStream stream = null; var sb = new StringBuilder(); var path = _dir + "Log"; if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } var str2 = path + @"\" + DateTime.Now.ToString("yyyy-MM-dd") + ".log"; sb.Append(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " "); sb.Append(msg); var bytes = Encoding.UTF8.GetBytes(sb + "\r\n"); try { if (!File.Exists(str2)) DeleteUnnecessaryLogFiles(); stream = File.OpenWrite(str2); stream.Position = stream.Length; stream.Write(bytes, 0, bytes.Length); } catch (Exception exception) { Console.WriteLine("文件打開失敗{0}", exception.Message); } finally { if (stream != null) stream.Close(); } } /// <summary> /// 字節數組寫入日志文件 /// </summary> /// <param name="msg">提示信息</param> /// <param name="data">字節數組</param> public void WriteLog_Bytes(string msg, byte[] data) { FileStream stream = null; var sb = new StringBuilder(); var path = _dir + @"\Log"; if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } var str2 = path + @"\" + DateTime.Now.ToString("yyyy-MM-dd") + ".log"; sb.Append(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " "); sb.Append(msg); foreach (var num in data) { sb.AppendFormat("{0:x2} ", num); } var bytes = Encoding.UTF8.GetBytes(sb + "\r\n"); try { if (!File.Exists(str2)) DeleteUnnecessaryLogFiles(); stream = File.OpenWrite(str2); stream.Position = stream.Length; stream.Write(bytes, 0, bytes.Length); } catch (Exception exception) { Console.WriteLine("文件打開失敗{0}", exception.Message); } finally { if (stream != null) stream.Close(); } } /// <summary> /// 刪除Log目錄多余的日志文件 /// </summary> public void DeleteUnnecessaryLogFiles() { var path = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory + @"Log\"); var fileInfos = path.GetFiles("*.log"); Array.Sort(fileInfos, new FileSorter()); if (fileInfos.Length <= (_maxLogNum - 1)) return; for (var i = _maxLogNum - 1; i < fileInfos.Length; i++) { var filepath = fileInfos[i].FullName; if (!File.Exists(filepath)) continue; try { File.Delete(filepath); } catch (Exception) { return; } } } } }
當前日志類不夠完善,我還沒有加上文件超過固定大小(如超出2M)自動創建新文件等等必要的功能,後續會逐漸完善。大家有什麼好建議,歡迎大家拍磚,哈哈。
如果要操作一個不斷增長的字符串,盡量不用String類,改用StringBuilder類。兩個類的工作原理不同:String類是一種傳統的修改字符串的方式,它確實可以完成把一個字符串添加到另一個字符串上的工作沒錯,但是在.NET框架下,這個操作實在是劃不來。因為系統先是把兩個字符串寫入內存,接著刪除原來的String對象,然後創建一個String對象,並讀取內存中的數據賦給該對象。這一來二去的,耗了不少時間。而使用System.Text命名空間下面的StringBuilder類就不是這樣了,它提供的Append方法,能夠在已有對象的原地進行字符串的修改,簡單而且直接。當然,一般情況下覺察不到這二者效率的差異,但如果你要對某個字符串進行大量的添加操作,那麼StringBuilder類所耗費的時間和String類簡直不是一個數量級的。
String是一個Unicode字符的有序集合,用於表示文本。一個字符串對象的有序集合系統.。字符對象代表一個字符串。字符串的值對象的內容是有序集合,這個價值是不可變的。 一個字符串對象稱為不變的(只讀),因為它的價值不能修改一旦建立。方法,似乎修改一個字符串對象實際上會返回一個新字符串對象,其中包含修改;
StringBuilder這個類代表一個可變的字符序列。據說這個值是可變的,因為它可以修改一旦建立通過添加,刪除,替換,或者插入字符。相比之下,看到String類。 大部分的方法,這些方法可以修改這個類的實例返回一個引用相同的實例。因為一個引用返回的實例,可以調用一個方法或屬性引用。這可以方便,如果你想寫一個聲明,一個接一個鏈連續操作。 一個StringBuilder的能力的最大字符數的實例可以存儲在任何給定的時間,和大於或等於字符串的長度表示值的實例;
如果有必要修改實際內容的一個線狀對象,使用StringBuilder類。