StreamWriter与FileStream的关闭

时间:2021-01-14 23:48:04
StreamWriter sw =File.CreateText(path);
//写入
sw.Close();


当我们创建一个StreamWriter,使用完成后,直接关闭即可。
但当我们先创建一个FileStream,在此基础上再创建一个StreamWriter,却需要先关闭StreamWriter,再关闭FileStream,如下:
FileStream fs = File.Open(path, FileMode.OpenOrCreate);
StreamWriter sw1 = new StreamWriter(fs);
//写入
sw1.Close();
 fs.Close();


第二种方法需要先打开文件,再进行写操作。再关闭写的流,然后关闭文件流。
而第一种方法只需要关闭写的流,难道它不需要打开和关闭文件吗?

8 个解决方案

#1


第2种方式是用流去创建流,按照微软示例只需要关闭后者即可,但一般谨慎起见会加上前者的关闭,打开关闭成对也便于代码阅读。
msdn示例:https://msdn.microsoft.com/zh-cn/library/wtbhzte9(v=vs.80).aspx

#2


StreamWriter与FileStream的关闭
所以说fs关闭后 sw1 并没有什么卵用
其实流也就只有一个而已 不是因为你创建了多少个类 就有多少个流
sw1 只是继承的fs 的流而已 所以fs关闭后 sw1就没有什么卵用了
而且我一般也不使用你后面这种写法 看着别扭

using(StreamReader reader = new StreamReader(path,Encoding.UTF8)){

}

#3


首先这两种方法的Close函数是不一样的。StreamWriter 并不是Stream的子类,它是一个封装好的类,功能是向流里面写入字符。
StreamWriter与FileStream的关闭因此它的close方法和Stream类是不一样的,当调用它的close函数的时候,它会是否自己占用的所有资源,包括流,所以。
而第二种,则是关闭实例化了的Stream子类,也就是你说的关闭流。

#4


在StreamWriter类中包含一个私有的Stream,
如果你使用public StreamWriter(string path);这个构造函数,StreamWriter会主动创建一个FileStream
如果你使用public StreamWriter(Stream stream);这个构造函数,StreamWriter则不会再创建FileStream而是直接使用你传入的Stream 。

其次,无论你是使用的哪个构造函数,StreamWriter在Close的时候都会关闭FileStream。
你可以尝试如下代码:
            FileStream fs = new FileStream(@"D:\test.txt" , FileMode.OpenOrCreate);
            StreamWriter sw = new StreamWriter(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的源代码。

其实,在这种多重复用关系的对象中,都要遵循一个先创建,后关闭的原则。即先进后出,后进先出。就像栈一样。

#5


部分关键代码:

    internal StreamWriter(string path, bool append, Encoding encoding, int bufferSize, bool checkHost)
      : base((IFormatProvider) null)
    {
      if (path == null)
        throw new ArgumentNullException("path");
      if (encoding == null)
        throw new ArgumentNullException("encoding");
      if (path.Length == 0)
        throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"));
      if (bufferSize <= 0)
        throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
      this.Init(StreamWriter.CreateFile(path, append, checkHost), encoding, bufferSize, false);
    }

    /// <summary>
    /// 用指定的编码及默认缓冲区大小,为指定的流初始化 <see cref="T:System.IO.StreamWriter"/> 类的新实例,有选择性的打开流。
    /// </summary>
    /// <param name="stream">要写入的流。</param><param name="encoding">要使用的字符编码。</param><param name="bufferSize">缓冲区大小(以字节为单位)。</param><param name="leaveOpen">如果在释放 <see cref="T:System.IO.StreamWriter"/> 对象之后打开流对象,则为 true;否则为, false。</param><exception cref="T:System.ArgumentNullException"><paramref name="stream"/> 或 <paramref name="encoding"/> 为 null。</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="bufferSize"/> 为负。</exception><exception cref="T:System.ArgumentException"><paramref name="stream"/> 不可写。</exception>
    [__DynamicallyInvokable]
    public StreamWriter(Stream stream, Encoding encoding, int bufferSize, bool leaveOpen)
      : base((IFormatProvider) null)
    {
      if (stream == null || encoding == null)
        throw new ArgumentNullException(stream == null ? "stream" : "encoding");
      if (!stream.CanWrite)
        throw new ArgumentException(Environment.GetResourceString("Argument_StreamNotWritable"));
      if (bufferSize <= 0)
        throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
      this.Init(stream, encoding, bufferSize, leaveOpen);
    }

  /// <summary>
    /// 关闭当前的 StreamWriter 对象和基础流。
    /// </summary>
    /// <exception cref="T:System.Text.EncoderFallbackException">当前编码不支持显示半个 Unicode 代理项对。</exception><filterpriority>1</filterpriority>
    public override void Close()
    {
      this.Dispose(true);
      GC.SuppressFinalize((object) this);
    }

    /// <summary>
    /// 释放由 <see cref="T:System.IO.StreamWriter"/> 占用的非托管资源,还可以另外再释放托管资源。
    /// </summary>
    /// <param name="disposing">true 表示释放托管资源和非托管资源;false 表示仅释放非托管资源。</param><exception cref="T:System.Text.EncoderFallbackException">当前编码不支持显示半个 Unicode 代理项对。</exception>
    [__DynamicallyInvokable]
    protected override void Dispose(bool disposing)
    {
      try
      {
        if (this.stream == null || !disposing && (!this.LeaveOpen || !(this.stream is __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);
            }
          }
        }
      }
    }

#6


是的!应该通过看源代码来学习 .net。许多时候,源代码跟自己推理、眼睛看到的都有差别。

写 fs.Close() 其实是多余的写法,只不过不会报错而已。大多数人都会有担心,所以写它也无妨,.net 也支持你多余地写 fs.Close()。然而从原理上看,StreamWriter 在 Close 时会额外地去调用 stream 的 Close方法。

#7


第二种你关闭fs都是多余的,请阅读StreamWriter.Close的作用
https://msdn.microsoft.com/zh-cn/library/system.io.streamwriter.close%28v=vs.80%29.aspx

#8


StreamWriter 执行 Close 的时候就会去执行 Dispose,而执行 Dispose 的时候就会去执行 Flush 并且再将当初做为参数的 stream 也给 Close 了。但是为了简单,我们通常写
using(FileStream fs = File.Open(path, FileMode.OpenOrCreate))
using(StreamWriter sw1 = new StreamWriter(fs))
{
    ....... 使用 sw1 的操作
};

这可以确保调用 Dispose。不用调用 Close,调用 dispose 就够了。

如果不写,显然 GC 回收 StreamWriter 对象时也会调用 Dispose 的,也会去 Flush 和 Close。但是那就有几秒钟延迟,而这个时候可能就会造成应用中某些地方的使用这些资源的代码抛出运行异常。

而如果你显示地去使用 using{  } 来调用 Dispose,从上面贴出的源代码看,它调用了 GC.SuppressFinalize((object) this),也就是说在 GC 回收 StreamWriter 对象时就不会额外去再调用 Close 方法了。

#1


第2种方式是用流去创建流,按照微软示例只需要关闭后者即可,但一般谨慎起见会加上前者的关闭,打开关闭成对也便于代码阅读。
msdn示例:https://msdn.microsoft.com/zh-cn/library/wtbhzte9(v=vs.80).aspx

#2


StreamWriter与FileStream的关闭
所以说fs关闭后 sw1 并没有什么卵用
其实流也就只有一个而已 不是因为你创建了多少个类 就有多少个流
sw1 只是继承的fs 的流而已 所以fs关闭后 sw1就没有什么卵用了
而且我一般也不使用你后面这种写法 看着别扭

using(StreamReader reader = new StreamReader(path,Encoding.UTF8)){

}

#3


首先这两种方法的Close函数是不一样的。StreamWriter 并不是Stream的子类,它是一个封装好的类,功能是向流里面写入字符。
StreamWriter与FileStream的关闭因此它的close方法和Stream类是不一样的,当调用它的close函数的时候,它会是否自己占用的所有资源,包括流,所以。
而第二种,则是关闭实例化了的Stream子类,也就是你说的关闭流。

#4


在StreamWriter类中包含一个私有的Stream,
如果你使用public StreamWriter(string path);这个构造函数,StreamWriter会主动创建一个FileStream
如果你使用public StreamWriter(Stream stream);这个构造函数,StreamWriter则不会再创建FileStream而是直接使用你传入的Stream 。

其次,无论你是使用的哪个构造函数,StreamWriter在Close的时候都会关闭FileStream。
你可以尝试如下代码:
            FileStream fs = new FileStream(@"D:\test.txt" , FileMode.OpenOrCreate);
            StreamWriter sw = new StreamWriter(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的源代码。

其实,在这种多重复用关系的对象中,都要遵循一个先创建,后关闭的原则。即先进后出,后进先出。就像栈一样。

#5


部分关键代码:

    internal StreamWriter(string path, bool append, Encoding encoding, int bufferSize, bool checkHost)
      : base((IFormatProvider) null)
    {
      if (path == null)
        throw new ArgumentNullException("path");
      if (encoding == null)
        throw new ArgumentNullException("encoding");
      if (path.Length == 0)
        throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"));
      if (bufferSize <= 0)
        throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
      this.Init(StreamWriter.CreateFile(path, append, checkHost), encoding, bufferSize, false);
    }

    /// <summary>
    /// 用指定的编码及默认缓冲区大小,为指定的流初始化 <see cref="T:System.IO.StreamWriter"/> 类的新实例,有选择性的打开流。
    /// </summary>
    /// <param name="stream">要写入的流。</param><param name="encoding">要使用的字符编码。</param><param name="bufferSize">缓冲区大小(以字节为单位)。</param><param name="leaveOpen">如果在释放 <see cref="T:System.IO.StreamWriter"/> 对象之后打开流对象,则为 true;否则为, false。</param><exception cref="T:System.ArgumentNullException"><paramref name="stream"/> 或 <paramref name="encoding"/> 为 null。</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="bufferSize"/> 为负。</exception><exception cref="T:System.ArgumentException"><paramref name="stream"/> 不可写。</exception>
    [__DynamicallyInvokable]
    public StreamWriter(Stream stream, Encoding encoding, int bufferSize, bool leaveOpen)
      : base((IFormatProvider) null)
    {
      if (stream == null || encoding == null)
        throw new ArgumentNullException(stream == null ? "stream" : "encoding");
      if (!stream.CanWrite)
        throw new ArgumentException(Environment.GetResourceString("Argument_StreamNotWritable"));
      if (bufferSize <= 0)
        throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
      this.Init(stream, encoding, bufferSize, leaveOpen);
    }

  /// <summary>
    /// 关闭当前的 StreamWriter 对象和基础流。
    /// </summary>
    /// <exception cref="T:System.Text.EncoderFallbackException">当前编码不支持显示半个 Unicode 代理项对。</exception><filterpriority>1</filterpriority>
    public override void Close()
    {
      this.Dispose(true);
      GC.SuppressFinalize((object) this);
    }

    /// <summary>
    /// 释放由 <see cref="T:System.IO.StreamWriter"/> 占用的非托管资源,还可以另外再释放托管资源。
    /// </summary>
    /// <param name="disposing">true 表示释放托管资源和非托管资源;false 表示仅释放非托管资源。</param><exception cref="T:System.Text.EncoderFallbackException">当前编码不支持显示半个 Unicode 代理项对。</exception>
    [__DynamicallyInvokable]
    protected override void Dispose(bool disposing)
    {
      try
      {
        if (this.stream == null || !disposing && (!this.LeaveOpen || !(this.stream is __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);
            }
          }
        }
      }
    }

#6


是的!应该通过看源代码来学习 .net。许多时候,源代码跟自己推理、眼睛看到的都有差别。

写 fs.Close() 其实是多余的写法,只不过不会报错而已。大多数人都会有担心,所以写它也无妨,.net 也支持你多余地写 fs.Close()。然而从原理上看,StreamWriter 在 Close 时会额外地去调用 stream 的 Close方法。

#7


第二种你关闭fs都是多余的,请阅读StreamWriter.Close的作用
https://msdn.microsoft.com/zh-cn/library/system.io.streamwriter.close%28v=vs.80%29.aspx

#8


StreamWriter 执行 Close 的时候就会去执行 Dispose,而执行 Dispose 的时候就会去执行 Flush 并且再将当初做为参数的 stream 也给 Close 了。但是为了简单,我们通常写
using(FileStream fs = File.Open(path, FileMode.OpenOrCreate))
using(StreamWriter sw1 = new StreamWriter(fs))
{
    ....... 使用 sw1 的操作
};

这可以确保调用 Dispose。不用调用 Close,调用 dispose 就够了。

如果不写,显然 GC 回收 StreamWriter 对象时也会调用 Dispose 的,也会去 Flush 和 Close。但是那就有几秒钟延迟,而这个时候可能就会造成应用中某些地方的使用这些资源的代码抛出运行异常。

而如果你显示地去使用 using{  } 来调用 Dispose,从上面贴出的源代码看,它调用了 GC.SuppressFinalize((object) this),也就是说在 GC 回收 StreamWriter 对象时就不会额外去再调用 Close 方法了。