2015-06-04 5 views
8

Grundsätzlich muss ich eine ZIP-Datei entpacken, die einen Ordner namens modelliert enthält, der wiederum eine Reihe von Excel-Dateien enthält.Wie entpacken Sie eine Zip-Datei mit Scala?

Ich hatte etwas Glück in der Suche nach Code, der bereits geschrieben wurde (ZipArchive), der die Zip-Datei entpacken soll, aber ich kann nicht herausfinden, warum es eine Fehlermeldung ausgibt, wenn ich es benutze. Der Code für ZipArchive und die Fehlermeldung sind unten aufgeführt:

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 
    } 
} 

Fehlermeldung:

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]  ... 

So auf der Grundlage der Fehlermeldung sieht es aus wie es versucht, die exportierte Excel-Datei zu finden? Dieser Teil wirft mich komplett ab. Jede Hilfe würde sehr geschätzt werden. Ich habe unten hinzugefügt, wie ich die Methode nenne, vielleicht mache ich etwas albern. Ich bin auch bereit, eine andere Art zu verwenden, um meine Zip-Datei zu extrahieren, wenn Sie eine empfehlen können.

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

Antwort

10

gut geht, da einige Dienstprogramme von Java verwenden, hier ist eine Version basen auf this, zu scala übersetzt, vielleicht sollte dies mehr funktionsfähig sein, aber es ist nützlich

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) 

} 
1
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 
    } 
} 
6

Hier ist eine funktionalere und präzisere Art und Weise dies zu tun

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

Der Versuch, mit Tian-Liang-Lösung zu arbeiten, ich reali zed, dass es nicht für Reißverschlüsse mit einer Verzeichnisstruktur funktioniert. Also nahm ich es auf diese Weise an:

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

Nur neugierig, ist es in Ordnung, das FileOutputStream Objekt nicht zu schließen? – costa

+0

Nach einigen Jahren würde ich annehmen, dass Sie Recht haben. Es ist immer sicherer, einen Ausgabestream zu schließen. :) –