使用ByteArrayOutputStream和ZipOutputStream无法将超过200MB的文件生成为ZIP

时间:2018-07-05 13:46:50

标签: java grails groovy bytearrayoutputstream zipoutputstream

我再次需要您的帮助。 我的应用程序尝试将用户的文件(设置,过程,标准文件等)导出为ZIP。此导出的ZIP稍后将用于在其他系统中导入用户的文件。 到目前为止,我已经完成了以下代码:

def files = File.findAllByUser(user)
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()
ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)

files.each { File it ->
   if (it.fileContent.content) {
      ZipEntry entry = new ZipEntry(user.name + "-" + it.id)
      entry.setSize(it.fileContent.content.length())

      zipOutputStream.putNextEntry(entry)
      zipOutputStream.write(it.fileContent.content.getBytes(1, it.fileContent.content.length() as int))
      zipOutputStream.closeEntry()
   } else {
      log.error("File ${it.id} has no content")
   }
}

我将文件另存为xml,然后另存为ZIP,保存在用户的备份目录中,如以下代码所示:

ZipEntry entry = new ZipEntry("${user}.xml")
entry.setSize(xml.bytes.length)
zipOutputStream.putNextEntry(entry)
zipOutputStream.write(xml.bytes)
zipOutputStream.closeEntry()
zipOutputStream.close()

Directory backupDir = Directory.findByUserAndIsBackupDirectory(userName, true)

File savedFile = new File(user: user, name: "${userName}.zip", contentType: "application/zip", directory: backupDir).save(flush: true, failOnError: true)
FileContent savedFileContent = new FileContent(file: savedFile).save(flush: true, failOnError: true)
savedFileContent.setDataBytes(outputStream.toByteArray())

到目前为止,它正在执行我们想要的操作,只是他们不保存超过200MB的文件。 我在这里错过了重要的事情吗?如何更改代码以保存大于200MB的文件?

1 个答案:

答案 0 :(得分:1)

对输出流进行分块处理,这样就不会尝试一次加载所有内容:

byte[] buffer = new byte[16 * 1024]
File zipFile = new File("myfile.zip")
zipFile.withOutputStream { OutputStream out ->
  ZipOutputStream zipOutputStream = new ZipOutputStream(out)
  File[] fileList = <<the list of files to zip>>
  fileList.each { File file ->
    zipOutputStream.putNextEntry(new ZipEntry(file.getName()))
    def inputStream = new FileInputStream(file)
    int len
    while ((len = inputStream.read(buffer)) > 0) {
      zipOutputStream.write(buffer, 0, len)
    }
    inputStream.close()
    zipOutputStream.closeEntry()
  }
  zipOutputStream.finish()
}