C# 高性能写文件 —— 只为挨砖

说到写文件,开源项目log4net对于.NET程序员来说恐怕是无人不知,本人一直想写一个性能高效的日志组件,但能力有限,因此来向大家学习,还望各位仁兄不吝赐教。

小弟写了一个简单的写文件的组件,经测试可以支撑5000的并发量(5000线程同时写同一个文件),再大的没测试,因为5000已经把CPU几乎沾满了。

贴出全部代码供大家探讨。

项目很简单,包含4个类:

FileAppender 基础类,提供写文件操作(私有)

IOLock 对读写线程锁的封装(私有)

Logger 对外提供写文件入口(公开)

Log 只是一个使用Logger的案例(公开)

代码如下:

View Code
1 using System;
2  using System.IO;
3  using System.Text;
4
5  namespace Zhuyi.IO
6 {
7 internal class FileAppender : IDisposable
8 {
9 private readonly IOLock io_lock = new IOLock();
10
11 private string f_name = string.Empty;//文件全路径
12   private Encoding f_encode = Encoding.Default;//文件编码
13  
14 private FileStream f_stream = null;
15 private StreamWriter writer = null;
16
17 private bool isAppend = false;//是否为追加模式
18   private readonly int reTimes = 5;//尝试读取次数
19
20 //为避免在写文件的过程将writer释放
21   private readonly object obj_lock = new object();
22
23 public FileAppender(string filename)
24 {
25 LastCallTime = DateTime.Now;
26
27 this.f_name = filename.Replace("/", "\\");
28
29 CheckDirectory();
30 }
31 public FileAppender(string filename, Encoding encode)
32 : this(filename)
33 {
34 this.f_encode = encode;
35 }
36 /// <summary>
37 /// 最后访问时间
38 /// </summary>
39   public DateTime LastCallTime { get; set; }
40
41 public void CallAddpender(string content, bool append)
42 {
43 if (f_stream == null || isAppend != append)
44 {
45 isAppend = append;
46
47 Reset();
48 }
49 io_lock.AcquireWriterLock();
50 lock (obj_lock)
51 {
52 try
53 {
54 writer.Write(content);
55 writer.Flush();
56 }
57 finally
58 {
59 io_lock.ReleaseWriterLock();
60 }
61 }
62 }
63 public void Dispose()
64 {
65 Close();
66 }
67
68 private void CheckDirectory()
69 {
70 string dir = f_name.Substring(0, f_name.LastIndexOf("\\"));
71 try
72 {
73 if (!Directory.Exists(dir))
74 {
75 Directory.CreateDirectory(dir);
76 }
77 }
78 catch (Exception ex)
79 {
80 throw ex;
81 }
82 }
83
84 private void Reset()
85 {
86 Close();
87 OpenFile(isAppend);
88 }
89 private void Close()
90 {
91 lock (obj_lock)
92 {
93 if (f_stream != null)
94 {
95 f_stream.Close();
96 f_stream.Dispose();
97 }
98 if (writer != null)
99 {
100 writer.Close();
101 writer.Dispose();
102 }
103 }
104 }
105
106 private void OpenFile(bool append)
107 {
108 Exception ex = null;
109 for (int i = 0; i < reTimes; i++)
110 {
111 try
112 {
113 f_stream = new FileStream(f_name,
114 (append ? FileMode.Append : FileMode.Create),
115 (append ? FileAccess.Write : FileAccess.ReadWrite),
116 FileShare.Read);
117 break;
118 }
119 catch (Exception e) { ex = e; }
120 }
121 if (f_stream == null)
122 throw ex;
123 else
124 writer = new StreamWriter(f_stream, f_encode);
125 }
126
127 }
128 }
View Code
1 using System;
2
3 namespace Zhuyi.IO
4 {
5 internal sealed class IOLock
6 {
7 private System.Threading.ReaderWriterLock m_lock;
8
9 public IOLock()
10 {
11 m_lock = new System.Threading.ReaderWriterLock();
12 }
13
14 public void AcquireReaderLock()
15 {
16 m_lock.AcquireReaderLock(-1);
17
18 //System.Threading.Monitor.Enter(this);
19 }
20
21 public void ReleaseReaderLock()
22 {
23 m_lock.ReleaseReaderLock();
24
25 //System.Threading.Monitor.Exit(this);
26 }
27
28 public void AcquireWriterLock()
29 {
30 m_lock.AcquireWriterLock(-1);
31
32 //System.Threading.Monitor.Enter(this);
33 }
34
35 public void ReleaseWriterLock()
36 {
37 m_lock.ReleaseWriterLock();
38
39 //System.Threading.Monitor.Exit(this);
40 }
41
42 }
43 }
View Code
1 using System;
2 using System.Text;
3 using System.Collections.Generic;
4 using System.Threading;
5
6 namespace Zhuyi.IO
7 {
8 public class Logger : IDisposable
9 {
10 private static Dictionary<string, FileAppender> logLst = new Dictionary<string, FileAppender>();
11 private const string NewLine = "\r\n";
12
13 #region 定时释放对象
14 private const double dSleep = 5;//停止访问某文件5秒后将其释放
15 private const int iPeriod = 5000;//计时器执行时间间隔
16 //定时器,用来定时释放不再使用的文件对象
17 private static readonly Timer timer = new Timer(new TimerCallback(TimerCall), null, iPeriod, iPeriod);
18
19 private static void TimerCall(object state)
20 {
21 DateTime now = DateTime.Now;
22 foreach (string key in logLst.Keys)
23 {
24 if ((now - logLst[key].LastCallTime).TotalSeconds > dSleep)
25 {
26 logLst[key].Dispose();
27 }
28 }
29 }
30 #endregion
31
32 public Logger(string filename)
33 {
34 this.FileName = filename;
35 }
36 public Logger(string filename, Encoding encode)
37 {
38 this.FileName = filename;
39 if (encode != null)
40 this.Encode = encode;
41 }
42
43 public string FileName { private get; set; }
44 public Encoding Encode { private get; set; }
45
46 public void Write(string content)
47 {
48 WriteText(content, false);
49 }
50 public void WriteLine(string content)
51 {
52 WriteText(content + NewLine, false);
53 }
54 public void Append(string content)
55 {
56 WriteText(content, true);
57 }
58 public void AppendLine(string content)
59 {
60 WriteText(content + NewLine, true);
61 }
62
63 private void WriteText(string content, bool append)
64 {
65 string filename = FileName.ToLower();
66 FileAppender logger = null;
67 lock (logLst)
68 {
69 if (logLst.ContainsKey(filename))
70 {
71 logger = logLst[filename];
72 }
73 else
74 {
75 logger = new FileAppender(FileName, Encode != null ? Encode : Encoding.Default);
76
77 logLst.Add(filename, logger);
78 }
79 }
80 logger.CallAddpender(content, append);
81
82 logger.LastCallTime = DateTime.Now;
83 }
84 public void Dispose()
85 {
86 string filename = FileName.ToLower();
87 if (logLst.ContainsKey(filename))
88 {
89 logLst[filename].Dispose();
90 logLst.Remove(filename);
91 }
92 }
93
94 }
95 }
View Code
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4
5 namespace Zhuyi.IO
6 {
7 public class Log
8 {
9 private static IDictionary<string, Logger> logLst = new Dictionary<string, Logger>();
10
11 public static void Write(string filename, string content, Encoding encode = null)
12 {
13 GetLogger(filename, encode).Write(content);
14 }
15
16 public static void Append(string filename, string content, Encoding encode = null)
17 {
18 GetLogger(filename, encode).Append(content);
19 }
20 public static void AppendLine(string filename, string content, Encoding encode = null)
21 {
22 GetLogger(filename, encode).AppendLine(content);
23 }
24
25 private static Logger GetLogger(string filename, Encoding encode)
26 {
27 Logger logger = null;
28 lock (logLst)
29 {
30 if (logLst.ContainsKey(filename.ToLower()))
31 {
32 logger = logLst[filename.ToLower()];
33 }
34 else
35 {
36 logger = new Logger(filename, encode);
37 logLst.Add(filename.ToLower(), logger);
38 }
39 }
40 return logger;
41 }
42 }
43 }

完整代码下载:

https://files.cnblogs.com/sqzhuyi/Zhuyi.IO.rar

请高手指点哪里需要改进。

posted on 2011-02-25 16:32  路人.乙  阅读(9072)  评论(31编辑  收藏  举报

导航