当我关闭 zipoutputstream 时,与其关联的 writer 对象是否也会被 GC 关闭和清理

When i close the zipoutputstream does the writer objects associated with it will also be closed and cleaned by GC

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

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

  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
  }

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

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

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

但是在这里,关闭操作的授权不是预期的,你必须注意关闭底层流。这很特别,但并不少见。当您拥有包含嵌入式子格式的文件格式或协议时,这总是会发生。 ZipOutputStream class 甚至还有一个 finish method 专用于将 zip 文件嵌入到另一个流中的场景。 PrintWriter没有这样的方法,另一方面,对于PrintWriter,调用flush()已经足以完成操作。

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