web-dev-qa-db-ja.com

Scalaを使用してZipファイルを解凍する方法

基本的に、modeledという名前のフォルダーを含む.Zipファイルを解凍する必要があります。このフォルダーには、多数のExcelファイルが含まれています。

Zipファイルを解凍するためのコード(ZipArchive)が既に記述されているコードを見つけるのは運が良かったのですが、使用するとエラーメッセージがスローされる理由がわかりません。 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
  }
}

エラーメッセージ:

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$1.apply$mcZ$sp(OepStepDefinitions.scala:175)
[error]     at com.contract.testing.OepStepDefinitions$$anonfun$1.apply(OepStepDefinitions.scala:150)
[error]     at com.contract.testing.OepStepDefinitions$$anonfun$1.apply(OepStepDefinitions.scala:150)
[error]     at cucumber.api.scala.ScalaDsl$StepBody$$anonfun$apply$1.applyOrElse(ScalaDsl.scala:61)
[error]     at cucumber.api.scala.ScalaDsl$StepBody$$anonfun$apply$1.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]     ...

エラーメッセージに基づいて、エクスポートされたExcelファイルを見つけようとしているように見えますか?この部分は私を完全に捨てます。どんな助けでも大歓迎です。メソッドを呼び出す方法を以下に追加しました。おそらくばかげたことをしています。また、推奨できる場合は、別の方法でZipファイルを抽出することもできます。

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

まあ、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)

}
12
anquegi

これはより機能的で正確な方法です

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, _))
}
20

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, _))
      }
    }
  }
12
Tom Fink
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
  }
}
3
Noel Yap

ここではゲームに遅れますが、scala.collection.JavaConvertersを利用してZipファイルエントリの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)
    }
  }
}
2
Steve

ZipFile.close()の自動呼び出しをSteveの回答にマージします。ノエルヤップの答えにある使​​用方法で作られています。

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)
      }
    }
  }
}
0
jseteny