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

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

 

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

 

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

 

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

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

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

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

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

 

代码如下:

using System; using System.IO; using System.Text; namespace Zhuyi.IO { internal class FileAppender : IDisposable { private readonly IOLock io_lock = new IOLock(); private string f_name = string.Empty;//文件全路径 private Encoding f_encode = Encoding.Default;//文件编码 private FileStream f_stream = null; private StreamWriter writer = null; private bool isAppend = false;//是否为追加模式 private readonly int reTimes = 5;//尝试读取次数 //为避免在写文件的过程将writer释放 private readonly object obj_lock = new object(); public FileAppender(string filename) { LastCallTime = DateTime.Now; this.f_name = filename.Replace("/", "//"); CheckDirectory(); } public FileAppender(string filename, Encoding encode) : this(filename) { this.f_encode = encode; } /// <summary> /// 最后访问时间 /// </summary> public DateTime LastCallTime { get; set; } public void CallAddpender(string content, bool append) { if (f_stream == null || isAppend != append) { isAppend = append; Reset(); } io_lock.AcquireWriterLock(); lock (obj_lock) { try { writer.Write(content); writer.Flush(); } finally { io_lock.ReleaseWriterLock(); } } } public void Dispose() { Close(); } private void CheckDirectory() { string dir = f_name.Substring(0, f_name.LastIndexOf("//")); try { if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } } catch (Exception ex) { throw ex; } } private void Reset() { Close(); OpenFile(isAppend); } private void Close() { lock (obj_lock) { if (f_stream != null) { f_stream.Close(); f_stream.Dispose(); } if (writer != null) { writer.Close(); writer.Dispose(); } } } private void OpenFile(bool append) { Exception ex = null; for (int i = 0; i < reTimes; i++) { try { f_stream = new FileStream(f_name, (append ? FileMode.Append : FileMode.Create), (append ? FileAccess.Write : FileAccess.ReadWrite), FileShare.Read); break; } catch (Exception e) { ex = e; } } if (f_stream == null) throw ex; else writer = new StreamWriter(f_stream, f_encode); } } }

using System; namespace Zhuyi.IO { internal sealed class IOLock { private System.Threading.ReaderWriterLock m_lock; public IOLock() { m_lock = new System.Threading.ReaderWriterLock(); } public void AcquireReaderLock() { m_lock.AcquireReaderLock(-1); //System.Threading.Monitor.Enter(this); } public void ReleaseReaderLock() { m_lock.ReleaseReaderLock(); //System.Threading.Monitor.Exit(this); } public void AcquireWriterLock() { m_lock.AcquireWriterLock(-1); //System.Threading.Monitor.Enter(this); } public void ReleaseWriterLock() { m_lock.ReleaseWriterLock(); //System.Threading.Monitor.Exit(this); } } }

using System; using System.Text; using System.Collections.Generic; using System.Threading; namespace Zhuyi.IO { public class Logger : IDisposable { private static Dictionary<string, FileAppender> logLst = new Dictionary<string, FileAppender>(); private const string NewLine = "/r/n"; #region 定时释放对象 private const double dSleep = 5;//停止访问某文件5秒后将其释放 private const int iPeriod = 5000;//计时器执行时间间隔 //定时器,用来定时释放不再使用的文件对象 private static readonly Timer timer = new Timer(new TimerCallback(TimerCall), null, iPeriod, iPeriod); private static void TimerCall(object state) { DateTime now = DateTime.Now; foreach (string key in logLst.Keys) { if ((now - logLst[key].LastCallTime).TotalSeconds > dSleep) { logLst[key].Dispose(); } } } #endregion public Logger(string filename) { this.FileName = filename; } public Logger(string filename, Encoding encode) { this.FileName = filename; if (encode != null) this.Encode = encode; } public string FileName { private get; set; } public Encoding Encode { private get; set; } public void Write(string content) { WriteText(content, false); } public void WriteLine(string content) { WriteText(content + NewLine, false); } public void Append(string content) { WriteText(content, true); } public void AppendLine(string content) { WriteText(content + NewLine, true); } private void WriteText(string content, bool append) { string filename = FileName.ToLower(); FileAppender logger = null; lock (logLst) { if (logLst.ContainsKey(filename)) { logger = logLst[filename]; } else { logger = new FileAppender(FileName, Encode != null ? Encode : Encoding.Default); logLst.Add(filename, logger); } } logger.CallAddpender(content, append); logger.LastCallTime = DateTime.Now; } public void Dispose() { string filename = FileName.ToLower(); if (logLst.ContainsKey(filename)) { logLst[filename].Dispose(); logLst.Remove(filename); } } } }

using System; using System.Collections.Generic; using System.Text; namespace Zhuyi.IO { public class Log { private static IDictionary<string, Logger> logLst = new Dictionary<string, Logger>(); public static void Write(string filename, string content, Encoding encode = null) { GetLogger(filename, encode).Write(content); } public static void Append(string filename, string content, Encoding encode = null) { GetLogger(filename, encode).Append(content); } public static void AppendLine(string filename, string content, Encoding encode = null) { GetLogger(filename, encode).AppendLine(content); } private static Logger GetLogger(string filename, Encoding encode) { Logger logger = null; lock (logLst) { if (logLst.ContainsKey(filename.ToLower())) { logger = logLst[filename.ToLower()]; } else { logger = new Logger(filename, encode); logLst.Add(filename.ToLower(), logger); } } return logger; } } }

完整代码下载:

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


作者:朱会震


  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值