由於程序是3層架構的,所有多線程記錄日志成了比較棘手的問題,以前還真就沒有在意過寫日志的問題,認為不過是寫文件罷了~~!如今發現原來要實現文件共享,並且能夠使多線程同時操作日志還不能相互沖突,真的很麻煩。當然要實現它我首先想到的是在網上搜,結果可能是我搜的不得其法,沒發現結果,多數都是用lock,mutx等線程鎖或互斥的方式寫日志,偶想這樣和單線程有啥區別嗎?還是沒能起到多線程應該有的效率!
后來問朋友,發現個log4net的東西,不過此物依然用到了線程互斥,看了源碼發現的!
網絡不行,朋友不知道,只好自己想辦法。想了幾種方法如下:
1、寫多個文件,然后找個機會把這些文件合並!
2、干脆放棄寫文件,改寫數據庫!
3、把文件看成一個表結構,實現行級鎖。也就是一個線程寫一行。
4、把文件看成內存塊,每塊寫完再合並!
以上幾種方法缺點:
1、多個文件。。。想起來就惡心!
2、寫數據庫?太沒技術含量咱不干!
3、行級鎖?我一個線程要寫入多行不是看起來很亂?
4、沒想到啥缺點,實現它吧!
以下是偶經過了10000線程並發測試,也沒發現問題的代碼!
- using System;
- using System.Collections.Generic;
- using System.Text;
- namespace MTW
- {
- public class MTWFile
- {
- private string _fileName;
- private static Dictionary<long, long> lockDic = new Dictionary<long, long>();
- /// <summary>
- /// 獲取或設置文件名稱
- /// </summary>
- public string FileName
- {
- get { return _fileName; }
- set { _fileName = value; }
- }
- /// <summary>
- /// 構造函數
- /// </summary>
- /// <param name="byteCount">每次開辟位數大小,這個直接影響到記錄文件的效率</param>
- /// <param name="fileName">文件全路徑名</param>
- public MTWFile(string fileName)
- {
- _fileName = fileName;
- }
- /// <summary>
- /// 創建文件
- /// </summary>
- /// <param name="fileName"></param>
- public void Create(string fileName)
- {
- if (!System.IO.File.Exists(fileName))
- {
- using (System.IO.FileStream fs = System.IO.File.Create(fileName))
- {
- fs.Close();
- }
- }
- }
- /// <summary>
- /// 寫入文本
- /// </summary>
- /// <param name="content">文本內容</param>
- private void Write(string content, string newLine)
- {
- if (string.IsNullOrEmpty(_fileName))
- {
- throw new Exception("FileName不能為空!");
- }
- using (System.IO.FileStream fs = new System.IO.FileStream(_fileName, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite, System.IO.FileShare.ReadWrite, 8, System.IO.FileOptions.Asynchronous))
- {
- //Byte[] dataArray = System.Text.Encoding.ASCII.GetBytes(System.DateTime.Now.ToString() + content + "/r/n");
- Byte[] dataArray = System.Text.Encoding.Default.GetBytes(content + newLine);
- bool flag = true;
- long slen = dataArray.Length;
- long len = 0;
- while (flag)
- {
- try
- {
- if (len >= fs.Length)
- {
- fs.Lock(len, slen);
- lockDic[len] = slen;
- flag = false;
- }
- else
- {
- len = fs.Length;
- }
- }
- catch (Exception ex)
- {
- while (!lockDic.ContainsKey(len))
- {
- len += lockDic[len];
- }
- }
- }
- fs.Seek(len, System.IO.SeekOrigin.Begin);
- fs.Write(dataArray, 0, dataArray.Length);
- fs.Close();
- }
- }
- /// <summary>
- /// 寫入文件內容
- /// </summary>
- /// <param name="content"></param>
- public void WriteLine(string content)
- {
- this.Write(content, System.Environment.NewLine);
- }
- /// <summary>
- /// 寫入文件
- /// </summary>
- /// <param name="content"></param>
- public void Write(string content)
- {
- this.Write(content, "");
- }
- }
- }
調用起來很簡單,實例化,然后隨便調用一個write或writeLine方法!
