问题描述
StreamWritersw=File.CreateText(path);//写入sw.Close();
当我们创建一个StreamWriter,使用完成后,直接关闭即可。但当我们先创建一个FileStream,在此基础上再创建一个StreamWriter,却需要先关闭StreamWriter,再关闭FileStream,如下:FileStreamfs=File.Open(path,FileMode.OpenOrCreate);StreamWritersw1=newStreamWriter(fs);//写入sw1.Close();fs.Close();
第二种方法需要先打开文件,再进行写操作。再关闭写的流,然后关闭文件流。而第一种方法只需要关闭写的流,难道它不需要打开和关闭文件吗?
解决方案
解决方案二:
第2种方式是用流去创建流,按照微软示例只需要关闭后者即可,但一般谨慎起见会加上前者的关闭,打开关闭成对也便于代码阅读。msdn示例:https://msdn.microsoft.com/zh-cn/library/wtbhzte9(v=vs.80).aspx
解决方案三:
所以说fs关闭后sw1并没有什么卵用其实流也就只有一个而已不是因为你创建了多少个类就有多少个流sw1只是继承的fs的流而已所以fs关闭后sw1就没有什么卵用了而且我一般也不使用你后面这种写法看着别扭using(StreamReaderreader=newStreamReader(path,Encoding.UTF8)){}
解决方案四:
首先这两种方法的Close函数是不一样的。StreamWriter并不是Stream的子类,它是一个封装好的类,功能是向流里面写入字符。因此它的close方法和Stream类是不一样的,当调用它的close函数的时候,它会是否自己占用的所有资源,包括流,所以。而第二种,则是关闭实例化了的Stream子类,也就是你说的关闭流。
解决方案五:
在StreamWriter类中包含一个私有的Stream,如果你使用publicStreamWriter(stringpath);这个构造函数,StreamWriter会主动创建一个FileStream如果你使用publicStreamWriter(Streamstream);这个构造函数,StreamWriter则不会再创建FileStream而是直接使用你传入的Stream。其次,无论你是使用的哪个构造函数,StreamWriter在Close的时候都会关闭FileStream。你可以尝试如下代码:FileStreamfs=newFileStream(@"D:test.txt",FileMode.OpenOrCreate);StreamWritersw=newStreamWriter(fs);sw.Close();fs.Close();在sw.Close();执行完毕后,其实fs已经被关闭了。因此fs.Close();其实是可以省略的。当然,这样的写法不会有任何问题,因为Dispose不会被执行两次。但是,sw.Close();fs.Close();这两行代码不可以交换顺序,如果先执行fs.Close();再执行sw.Close();将引发异常。因为在StreamWriter的Close函数调用过程中,将调用Flush函数,而此时fs已经被关闭,Flush将产生异常。如果想详细了解,可以查看StreamWriter的源代码。其实,在这种多重复用关系的对象中,都要遵循一个先创建,后关闭的原则。即先进后出,后进先出。就像栈一样。
解决方案六:
部分关键代码:internalStreamWriter(stringpath,boolappend,Encodingencoding,intbufferSize,boolcheckHost):base((IFormatProvider)null){if(path==null)thrownewArgumentNullException("path");if(encoding==null)thrownewArgumentNullException("encoding");if(path.Length==0)thrownewArgumentException(Environment.GetResourceString("Argument_EmptyPath"));if(bufferSize<=0)thrownewArgumentOutOfRangeException("bufferSize",Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));this.Init(StreamWriter.CreateFile(path,append,checkHost),encoding,bufferSize,false);}///<summary>///用指定的编码及默认缓冲区大小,为指定的流初始化<seecref="T:System.IO.StreamWriter"/>类的新实例,有选择性的打开流。///</summary>///<paramname="stream">要写入的流。</param><paramname="encoding">要使用的字符编码。</param><paramname="bufferSize">缓冲区大小(以字节为单位)。</param><paramname="leaveOpen">如果在释放<seecref="T:System.IO.StreamWriter"/>对象之后打开流对象,则为true;否则为,false。</param><exceptioncref="T:System.ArgumentNullException"><paramrefname="stream"/>或<paramrefname="encoding"/>为null。</exception><exceptioncref="T:System.ArgumentOutOfRangeException"><paramrefname="bufferSize"/>为负。</exception><exceptioncref="T:System.ArgumentException"><paramrefname="stream"/>不可写。</exception>[__DynamicallyInvokable]publicStreamWriter(Streamstream,Encodingencoding,intbufferSize,boolleaveOpen):base((IFormatProvider)null){if(stream==null||encoding==null)thrownewArgumentNullException(stream==null?"stream":"encoding");if(!stream.CanWrite)thrownewArgumentException(Environment.GetResourceString("Argument_StreamNotWritable"));if(bufferSize<=0)thrownewArgumentOutOfRangeException("bufferSize",Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));this.Init(stream,encoding,bufferSize,leaveOpen);}///<summary>///关闭当前的StreamWriter对象和基础流。///</summary>///<exceptioncref="T:System.Text.EncoderFallbackException">当前编码不支持显示半个Unicode代理项对。</exception><filterpriority>1</filterpriority>publicoverridevoidClose(){this.Dispose(true);GC.SuppressFinalize((object)this);}///<summary>///释放由<seecref="T:System.IO.StreamWriter"/>占用的非托管资源,还可以另外再释放托管资源。///</summary>///<paramname="disposing">true表示释放托管资源和非托管资源;false表示仅释放非托管资源。</param><exceptioncref="T:System.Text.EncoderFallbackException">当前编码不支持显示半个Unicode代理项对。</exception>[__DynamicallyInvokable]protectedoverridevoidDispose(booldisposing){try{if(this.stream==null||!disposing&&(!this.LeaveOpen||!(this.streamis__ConsoleStream)))return;this.CheckAsyncTaskInProgress();this.Flush(true,true);if(this.mdaHelper==null)return;GC.SuppressFinalize((object)this.mdaHelper);}finally{if(!this.LeaveOpen){if(this.stream!=null){try{if(disposing)this.stream.Close();}finally{this.stream=(Stream)null;this.byteBuffer=(byte[])null;this.charBuffer=(char[])null;this.encoding=(Encoding)null;this.encoder=(Encoder)null;this.charLen=0;base.Dispose(disposing);}}}}}
解决方案七:
是的!应该通过看源代码来学习.net。许多时候,源代码跟自己推理、眼睛看到的都有差别。写fs.Close()其实是多余的写法,只不过不会报错而已。大多数人都会有担心,所以写它也无妨,.net也支持你多余地写fs.Close()。然而从原理上看,StreamWriter在Close时会额外地去调用stream的Close方法。
解决方案八:
第二种你关闭fs都是多余的,请阅读StreamWriter.Close的作用
解决方案九:
StreamWriter执行Close的时候就会去执行Dispose,而执行Dispose的时候就会去执行Flush并且再将当初做为参数的stream也给Close了。但是为了简单,我们通常写using(FileStreamfs=File.Open(path,FileMode.OpenOrCreate))using(StreamWritersw1=newStreamWriter(fs)){.......使用sw1的操作};
这可以确保调用Dispose。不用调用Close,调用dispose就够了。如果不写,显然GC回收StreamWriter对象时也会调用Dispose的,也会去Flush和Close。但是那就有几秒钟延迟,而这个时候可能就会造成应用中某些地方的使用这些资源的代码抛出运行异常。而如果你显示地去使用using{}来调用Dispose,从上面贴出的源代码看,它调用了GC.SuppressFinalize((object)this),也就是说在GC回收StreamWriter对象时就不会额外去再调用Close方法了。