scala 如何使用scala解压缩zip文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30640627/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 07:13:02  来源:igfitidea点击:

How to unzip a zip file using scala?

excelscalaunzip

提问by user4659009

Basically I need to unzip a .zip file which contains a folder called modeled which in turn contains a number of excel files.

基本上我需要解压缩一个 .zip 文件,其中包含一个名为 modeled 的文件夹,该文件夹又包含许多 excel 文件。

I have had some luck in finding code that was already written (ZipArchive) which is meant to unzip the zip file, but I cannot figure out why it throws an error message when I use it. The code for ZipArchive and the error message are listed below:

我很幸运地找到了已经编写好的代码 (ZipArchive),该代码旨在解压缩 zip 文件,但我无法弄清楚为什么在使用它时会抛出错误消息。下面列出了 ZipArchive 的代码和错误消息:

import java.io.{OutputStream, InputStream, File, FileOutputStream}
import java.util.zip.{ZipEntry, ZipFile}
import scala.collection.JavaConversions._

object ZipArchive {

  val BUFSIZE = 4096
  val buffer = new Array[Byte](BUFSIZE)

  def unZip(source: String, targetFolder: String) = {
    val zipFile = new ZipFile(source)

    unzipAllFile(zipFile.entries.toList, getZipEntryInputStream(zipFile)_, new File(targetFolder))
  }

  def getZipEntryInputStream(zipFile: ZipFile)(entry: ZipEntry) = zipFile.getInputStream(entry)

  def unzipAllFile(entryList: List[ZipEntry], inputGetter: (ZipEntry) => InputStream, targetFolder: File): Boolean = {

    entryList match {
      case entry :: entries =>

        if (entry.isDirectory)
          new File(targetFolder, entry.getName).mkdirs
        else
          saveFile(inputGetter(entry), new FileOutputStream(new File(targetFolder, entry.getName)))

        unzipAllFile(entries, inputGetter, targetFolder)
      case _ =>
        true
    }
  }

  def saveFile(fis: InputStream, fos: OutputStream) = {
    writeToFile(bufferReader(fis)_, fos)
    fis.close
    fos.close
  }

  def bufferReader(fis: InputStream)(buffer: Array[Byte]) = (fis.read(buffer), buffer)

  def writeToFile(reader: (Array[Byte]) => Tuple2[Int, Array[Byte]], fos: OutputStream): Boolean = {
    val (length, data) = reader(buffer)
    if (length >= 0) {
      fos.write(data, 0, length)
      writeToFile(reader, fos)
    } else
      true
  }
}

Error Message:

错误信息:

java.io.FileNotFoundException: src/test/resources/oepTemp/modeled/EQ_US_2_NULL_('CA')_ALL_ELT_IL_EQ_US.xlsx (No such file or directory), took 6.406 sec
[error]     at java.io.FileOutputStream.open(Native Method)
[error]     at java.io.FileOutputStream.<init>(FileOutputStream.java:221)
[error]     at java.io.FileOutputStream.<init>(FileOutputStream.java:171)
[error]     at com.contract.testing.ZipArchive$.unzipAllFile(ZipArchive.scala:28)
[error]     at com.contract.testing.ZipArchive$.unZip(ZipArchive.scala:15)
[error]     at com.contract.testing.OepStepDefinitions$$anonfun.apply$mcZ$sp(OepStepDefinitions.scala:175)
[error]     at com.contract.testing.OepStepDefinitions$$anonfun.apply(OepStepDefinitions.scala:150)
[error]     at com.contract.testing.OepStepDefinitions$$anonfun.apply(OepStepDefinitions.scala:150)
[error]     at cucumber.api.scala.ScalaDsl$StepBody$$anonfun$apply.applyOrElse(ScalaDsl.scala:61)
[error]     at cucumber.api.scala.ScalaDsl$StepBody$$anonfun$apply.applyOrElse(ScalaDsl.scala:61)
[error]     at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:36)
[error]     at cucumber.runtime.scala.ScalaStepDefinition.execute(ScalaStepDefinition.scala:71)
[error]     at cucumber.runtime.StepDefinitionMatch.runStep(StepDefinitionMatch.java:37)
[error]     at cucumber.runtime.Runtime.runStep(Runtime.java:298)
[error]     at cucumber.runtime.model.StepContainer.runStep(StepContainer.java:44)
[error]     at cucumber.runtime.model.StepContainer.runSteps(StepContainer.java:39)
[error]     at cucumber.runtime.model.CucumberScenario.run(CucumberScenario.java:48)
[error]     at cucumber.runtime.junit.ExecutionUnitRunner.run(ExecutionUnitRunner.java:91)
[error]     at cucumber.runtime.junit.FeatureRunner.runChild(FeatureRunner.java:63)
[error]     at cucumber.runtime.junit.FeatureRunner.runChild(FeatureRunner.java:18)
[error]     ...

So based on the error message it looks like it's trying to find the exported excel file? This part completely throws me off. Any help would be greatly appreciated. I've added below how I'm calling the method, perhaps I'm doing something silly. Also I'm up for using a different way to extract my zip file if you can recommend one.

因此,根据错误消息,它似乎正在尝试查找导出的 excel 文件?这部分完全让我失望。任何帮助将不胜感激。我在下面添加了我如何调用该方法,也许我在做一些愚蠢的事情。如果您能推荐一种方式,我也准备使用不同的方式来提取我的 zip 文件。

val tempDirectoryDir = "src/test/resources/oepTemp/"
ZipArchive.unZip(tempDirectoryDir + "Sub Region Input - Output.zip", tempDirectoryDir)

采纳答案by anquegi

Well since were are using some utilities from java, here is a version basen on this, translated to scala, maybe this should be more functional, but it is useful

好吧,因为使用了一些来自 java 的实用程序,这里有一个基于this的版本,翻译成 Scala,也许这应该更实用,但它很有用

package zip

import java.io.{ IOException, FileOutputStream, FileInputStream, File }
import java.util.zip.{ ZipEntry, ZipInputStream }

/**
 * Created by anquegi on 04/06/15.
 */
object Unzip extends App {

  val INPUT_ZIP_FILE: String = "src/main/resources/my-zip.zip";
  val OUTPUT_FOLDER: String = "src/main/resources/my-zip";

  def unZipIt(zipFile: String, outputFolder: String): Unit = {

    val buffer = new Array[Byte](1024)

    try {

      //output directory
      val folder = new File(OUTPUT_FOLDER);
      if (!folder.exists()) {
        folder.mkdir();
      }

      //zip file content
      val zis: ZipInputStream = new ZipInputStream(new FileInputStream(zipFile));
      //get the zipped file list entry
      var ze: ZipEntry = zis.getNextEntry();

      while (ze != null) {

        val fileName = ze.getName();
        val newFile = new File(outputFolder + File.separator + fileName);

        System.out.println("file unzip : " + newFile.getAbsoluteFile());

        //create folders
        new File(newFile.getParent()).mkdirs();

        val fos = new FileOutputStream(newFile);

        var len: Int = zis.read(buffer);

        while (len > 0) {

          fos.write(buffer, 0, len)
          len = zis.read(buffer)
        }

        fos.close()
        ze = zis.getNextEntry()
      }

      zis.closeEntry()
      zis.close()

    } catch {
      case e: IOException => println("exception caught: " + e.getMessage)
    }

  }

  Unzip.unZipIt(INPUT_ZIP_FILE, OUTPUT_FOLDER)

}

回答by Tian-Liang Huang

Here's a more functional and precise way doing this

这是一个更实用和更精确的方法

import java.io.{FileInputStream, FileOutputStream}
import java.util.zip.ZipInputStream
val fis = new FileInputStream("htl.zip")
val zis = new ZipInputStream(fis)
Stream.continually(zis.getNextEntry).takeWhile(_ != null).foreach{ file =>
    val fout = new FileOutputStream(file.getName)
    val buffer = new Array[Byte](1024)
    Stream.continually(zis.read(buffer)).takeWhile(_ != -1).foreach(fout.write(buffer, 0, _))
}

回答by Tom Fink

Trying to work with Tian-Liang's solution, I realized that its not working for zips with a directory structure. So I adopted it this way:

尝试使用 Tian-Liang 的解决方案时,我意识到它不适用于具有目录结构的 zip。所以我采用了这种方式:

  import java.io.{FileOutputStream, InputStream}
  import java.nio.file.Path
  import java.util.zip.ZipInputStream

  def unzip(zipFile: InputStream, destination: Path): Unit = {
    val zis = new ZipInputStream(zipFile)

    Stream.continually(zis.getNextEntry).takeWhile(_ != null).foreach { file =>
      if (!file.isDirectory) {
        val outPath = destination.resolve(file.getName)
        val outPathParent = outPath.getParent
        if (!outPathParent.toFile.exists()) {
          outPathParent.toFile.mkdirs()
        }

        val outFile = outPath.toFile
        val out = new FileOutputStream(outFile)
        val buffer = new Array[Byte](4096)
        Stream.continually(zis.read(buffer)).takeWhile(_ != -1).foreach(out.write(buffer, 0, _))
      }
    }
  }

回答by Steve

Late to the game here, but I would take advantage of scala.collection.JavaConvertersto get a for-loop over the zip file entries, and java.nio.Filesto get simple copying and directory creation:

在这里玩游戏很晚,但我会利用对scala.collection.JavaConverterszip 文件条目进行 for 循环,并java.nio.Files进行简单的复制和目录创建:

import java.nio.file.{Files, Path}
import java.util.zip.ZipFile
import scala.collection.JavaConverters._

def unzip(zipPath: Path, outputPath: Path): Unit = {
  val zipFile = new ZipFile(zipPath.toFile)
  for (entry <- zipFile.entries.asScala) {
    val path = outputPath.resolve(entry.getName)
    if (entry.isDirectory) {
      Files.createDirectories(path)
    } else {
      Files.createDirectories(path.getParent)
      Files.copy(zipFile.getInputStream(entry), path)
    }
  }
}

回答by Noel Yap

import java.io.FileInputStream
import java.io.InputStream
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import scala.language.reflectiveCalls
import scala.util.Try

import org.apache.commons.io.IOUtils

def using[T <: { def close() }, U](resource: T)(block: T => U): U = {
  try {
    block(resource)
  } finally {
    if (resource != null) {
        resource.close()
    }
  }
}

def processZipFile(zipFile: ZipFile)(doStuff: ZipEntry => Unit) {
  using(new ZipInputStream(new FileInputStream(zipFile))) { zipInputStream =>
    val entries = Stream.continually(Try(zipInputStream.getNextEntry()).getOrElse(null))
        .takeWhile(_ != null) // while not EOF and not corrupted
        .foreach(doStuff)
        .force
  }
}

回答by jseteny

I would merge the automatic calling of ZipFile.close() into Steve's answer. It is made by the using method which is present in Noel Yap's answer.

我会将 ZipFile.close() 的自动调用合并到 Steve 的回答中。它是通过 Noel Yap 的回答中提供的使用方法制作的。

import java.nio.file.{Files, Path}
import java.util.zip.ZipFile
import scala.collection.JavaConverters._

def using[T <: {def close()}, U](resource: T)(block: T => U): U = {
  try {
    block(resource)
  } finally {
    if (resource != null) {
      resource.close()
    }
  }
}

def unzip(zipPath: Path, outputPath: Path): Unit = {
  using(new ZipFile(zipPath.toFile)) { zipFile =>
    for (entry <- zipFile.entries.asScala) {
      val path = outputPath.resolve(entry.getName)
      if (entry.isDirectory) {
        Files.createDirectories(path)
      } else {
        Files.createDirectories(path.getParent)
        Files.copy(zipFile.getInputStream(entry), path)
      }
    }
  }
}