如何获取StreamWriter已写字节数以实现文件滚动功能?
嘿,我来帮你搞定这个滚动文件的字节统计问题!要实现文件大小超限就自动切换的逻辑,核心就是准确拿到StreamWriter已经写入文件的字节数,这里有两个实用方案:
方案1:直接利用StreamWriter的基础流(简单快捷)
StreamWriter本身没直接提供已写入字节数的属性,但它包装的BaseStream(比如你用的FileStream)有个Position属性,这就是当前已写入文件的字节数。不过要注意必须先刷新缓冲区——StreamWriter有内置缓存,没刷新的话,Position不会同步最新的写入内容。
修改你的GetBytesWritten方法就行:
int GetBytesWritten(StreamWriter sw) { // 先把缓存里的内容刷到文件里,确保统计准确 sw.Flush(); // 把基础流转成FileStream(滚动文件场景下基本都是这个类型) if (sw.BaseStream is FileStream fileStream) { return (int)fileStream.Position; } throw new InvalidOperationException("当前StreamWriter的基础流不是FileStream,无法统计字节数"); }
方案2:自定义追踪型StreamWriter(更可靠的长期方案)
如果担心后续基础流类型变化,或者想更精准控制统计逻辑,不如自己封装一个能自动追踪字节数的StreamWriter,每次写入都自动累加字节数:
class TrackedStreamWriter : StreamWriter { private long _totalBytesWritten = 0; public long TotalBytesWritten => _totalBytesWritten; public TrackedStreamWriter(string filePath) : base(filePath) { } // 重写Write方法,统计写入字节数 public override void Write(string value) { // 用当前StreamWriter的编码计算字符串的字节数,确保统计准确 var byteCount = Encoding.GetByteCount(value); _totalBytesWritten += byteCount; base.Write(value); } // 别忘了重写WriteLine,因为它会多写换行符 public override void WriteLine(string value) { var fullContent = value + Environment.NewLine; var byteCount = Encoding.GetByteCount(fullContent); _totalBytesWritten += byteCount; base.WriteLine(value); } // 可选:刷新时同步一下实际文件的位置,避免缓存导致的统计偏差 public override void Flush() { base.Flush(); if (BaseStream is FileStream fs) { _totalBytesWritten = fs.Position; } } }
之后在你的RollingFile类里用这个TrackedStreamWriter,直接通过TotalBytesWritten属性就能拿到已写入字节数,不用每次都刷新和转换流,省心多了。
滚动逻辑的小提醒
在AppendMessage里,每次写入前先做判断:
void AppendMessage(TrackedStreamWriter writer, string message, long fileSizeLimit) { // 先算一下这次写入会增加多少字节 var messageByteCount = writer.Encoding.GetByteCount(message + Environment.NewLine); // 如果加上当前已写入的字节数超过限制,就切换文件 if (writer.TotalBytesWritten + messageByteCount > fileSizeLimit) { writer.Close(); // 这里自己实现生成新文件名的逻辑,比如加后缀_1、_2之类的 var newFilePath = GenerateNewRollingFileName(); writer = new TrackedStreamWriter(newFilePath); } writer.WriteLine(message); // 按需刷新,要是要求实时写入文件就加上,否则可以等缓冲区满了再自动刷 writer.Flush(); }
内容的提问来源于stack exchange,提问作者Mohit
相关产品推荐
相关产品推荐

