欢迎大家来到IT世界,在知识的湖畔探索吧!
前言
前一段时间,接手同事做的一个工具,该工具已经很长时间没有修改过了,前几天有反馈说,工具运行最近有点小问题.便对代码调试跟了一下,看看是哪里的问题.这不是重点,在调试的时候发现记录日志是抛异常的.
先看看这一块有没有问题:
测试代码:
private static void Main(string[] args)
{
try
{
Log.WriteLog("123.txt", "hello csharp");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
欢迎大家来到IT世界,在知识的湖畔探索吧!
说一下,调用文件流的Dispose方法,是没有问题的,那为什么会出现异常呢?是调用StreamWriter.Close方法时报的异常.这里应该这样写.
欢迎大家来到IT世界,在知识的湖畔探索吧!public static void WriteLog(string fileName, string log)
{
string filePath = Path.Combine(Directory.GetCurrentDirectory(), fileName);
FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write);
StreamWriter sw = new StreamWriter(fs);
try
{
sw.BaseStream.Seek(0, SeekOrigin.End);
sw.WriteLine(log);
sw.Flush();
}
finally
{
sw.Close(); //先对StreamWriter进行关闭
fs.Dispose(); //再对FileStream进行释放
}
}
接着我们看看StreamWriter的Close源码:
public override void Close()
{
Dispose(true); //调用StreamWriter的Dispose
GC.SuppressFinalize(this);
}
protected override void Dispose(bool disposing)
{
try
{
// We need to flush any buffered data if we are being closed/disposed.
// Also, we never close the handles for stdout & friends. So we can safely
// write any buffered data to those streams even during finalization, which
// is generally the right thing to do.
if (!_disposed && disposing)
{
// Note: flush on the underlying stream can throw (ex., low disk space)
CheckAsyncTaskInProgress();
Flush(flushStream: true, flushEncoder: true); //调用Flush将缓冲区的数据写入到文件流中,如果先调用FileStream的Dispose进行释放,在这里提示文件关闭
}
}
finally
{
CloseStreamFromDispose(disposing);
}
}
private void CloseStreamFromDispose(bool disposing)
{
// Dispose of our resources if this StreamWriter is closable.
if (_closable && !_disposed)
{
try
{
// Attempt to close the stream even if there was an IO error from Flushing.
// Note that Stream.Close() can potentially throw here (may or may not be
// due to the same Flush error). In this case, we still need to ensure
// cleaning up internal resources, hence the finally block.
if (disposing)
{
_stream.Close(); //将缓冲区数据写入到文件流中,会对文件流进行关闭,
//_stream就是在实例化StreamWriter传入的FileStream
}
}
finally
{
_disposed = true;
_charLen = 0;
base.Dispose(disposing);
}
}
}
接着看Flush方法源码:
欢迎大家来到IT世界,在知识的湖畔探索吧!private void Flush(bool flushStream, bool flushEncoder)
{
// flushEncoder should be true at the end of the file and if
// the user explicitly calls Flush (though not if AutoFlush is true).
// This is required to flush any dangling characters from our UTF-7
// and UTF-8 encoders.
ThrowIfDisposed(); //判断文件流是否关闭,如果关闭抛出异常
// Perf boost for Flush on non-dirty writers.
if (_charPos == 0 && !flushStream && !flushEncoder)
{
return;
}
if (!_haveWrittenPreamble)
{
_haveWrittenPreamble = true;
ReadOnlySpan<byte> preamble = _encoding.Preamble;
if (preamble.Length > 0)
{
_stream.Write(preamble);
}
}
// For sufficiently small char data being flushed, try to encode to the stack.
// For anything else, fall back to allocating the byte[] buffer.
scoped Span<byte> byteBuffer;
if (_byteBuffer is not null)
{
byteBuffer = _byteBuffer;
}
else
{
int maxBytesForCharPos = _encoding.GetMaxByteCount(_charPos);
byteBuffer = maxBytesForCharPos <= 1024 ? // arbitrary threshold
stackalloc byte[1024] :
(_byteBuffer = new byte[_encoding.GetMaxByteCount(_charBuffer.Length)]);
}
int count = _encoder.GetBytes(new ReadOnlySpan<char>(_charBuffer, 0, _charPos), byteBuffer, flushEncoder);
_charPos = 0;
if (count > 0)
{
_stream.Write(byteBuffer.Slice(0, count));
}
if (flushStream)
{
_stream.Flush();
}
}
图1中代码运行抛出异常,主要是对FileStream释放的时机问题.可以使用简化代码:
public static void WriteLog2(string fileName, string log)
{
string filePath = Path.Combine(Directory.GetCurrentDirectory(), fileName);
using (FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write))
{
using (StreamWriter sw = new StreamWriter(fs))
{
sw.BaseStream.Seek(0, SeekOrigin.End);
sw.WriteLine(log);
sw.Flush();
}
}
}
其实在很早之前在文章中也提到过文件释放, 具体可以看看: 写更好的CSharp代码
个人能力有限,如果您发现有什么不对,请私信我
如果您觉得对您有用的话,可以点个赞或者加个关注,欢迎大家一起进行技术交流
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/37400.html