首页 > 解决方案 > 当我关闭 zipoutputstream 时,与之关联的写入器对象是否也会被 GC 关闭和清理

问题描述

尝试创建一个包含 3 个文件的 ZIP 文件。我正在使用 ZipOutputStream 创建 ZIP 文件,使用 Printwriter 创建文件并将其写入 Zip。

当我在写入文件后关闭 printwriter 对象时也会关闭流,我知道。但是,如果我在写入 zip 后关闭 zip 输出流,它也会关闭并清理我的打印机对象

  def main(args: Array[String]): Unit = {
    val file: File = new File("Hello.zip")
    val zos: ZipOutputStream = new ZipOutputStream(new FileOutputStream(file))
    val fileNames = Array("Happy1.csv", "Happy2.csv", "Happy3.csv", "Happy4.csv")
    fileNames.foreach { tempfile =>
      zos.putNextEntry(new ZipEntry(tempfile))
      Try {
        val writer = new PrintWriter(new OutputStreamWriter(zos))
        writer.println("Hello,World")
        writer.flush()
        // writer.close() // Closing writer closes the stream so commented it
      }
    }
    zos.closeEntry()
    zos.flush()
    zos.close() // will my writer object also closed and cleaned by gc
  }

标签: scalastreamgarbage-collectionprintwriterzipoutputstream

解决方案


关闭ZipOutputStream不会关闭PrintWriternor OutputStreamWriter;事实上,它甚至不知道这些作家的存在。引用指向另一种方式,PrintWriter具有对OutputStreamWriter将委托写入、刷新和关闭操作的 的引用,就像OutputStreamWriter将委托给ZipOutputStream.

但是PrintWriterOutputStreamWriter不承担任何系统资源,除了那些被目标输出流封装的资源,即ZipOutputStream. 当您调用flush()强制写入任何未决数据时,您已经完成了清理所需的一切,因为您ZipOutputStream最后关闭了。

通常,您使用装饰流或编写器来控制生命周期,有时甚至不保留对封装流或编写器的引用。所以关闭装饰流或作家是强制性的。

但是在这里,如果不打算委托关闭操作,则必须注意关闭底层流。这很特殊,但并不少见。当您拥有带有嵌入子格式的文件格式或协议时,总是会发生这种情况。该类ZipOutputStream甚至有一个完成方法,专用于将 zip 文件嵌入到另一个流中的场景。PrintWriter另一方面,没有这样的方法,对于 a PrintWriter,调用flush()已经足够完成操作了。

请注意,您应该使用 Scala 等效的try-with-resources来关闭ZipOutputStream,如果有的话。进一步注意,如果您在每个条目的末尾PrintWriter继续关注它,您可以在整个操作中使用相同的。flush这将允许在最后关闭它,就像在简单的包装流场景中一样。


推荐阅读