如何使用 scala 解压缩 zip 文件?
How to unzip a zip file using scala?
基本上我需要解压缩一个 .zip 文件,其中包含一个名为 modeled 的文件夹,该文件夹又包含许多 excel 文件。
我很幸运地找到了已经编写好的代码 (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
}
}
错误信息:
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] ...
所以根据错误消息,它似乎在尝试查找导出的 excel 文件?这部分完全让我失望。任何帮助将不胜感激。
我在下面添加了我如何调用该方法,也许我在做一些愚蠢的事情。如果您可以推荐的话,我也准备使用其他方法来提取我的 zip 文件。
val tempDirectoryDir = "src/test/resources/oepTemp/"
ZipArchive.unZip(tempDirectoryDir + "Sub Region Input - Output.zip", tempDirectoryDir)
既然我们正在使用 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)
}
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
}
}
这是一种更实用、更精确的方法
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, _))
}
尝试使用 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, _))
}
}
}
来晚了,但我会利用 scala.collection.JavaConverters
在 zip 文件条目上获得 for-loop,并利用 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)
}
}
}
我会将 ZipFile.close() 的自动调用合并到史蒂夫的答案中。它是通过 Noel Yap 的回答中提供的 using 方法制作的。
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)
}
}
}
}
基本上我需要解压缩一个 .zip 文件,其中包含一个名为 modeled 的文件夹,该文件夹又包含许多 excel 文件。
我很幸运地找到了已经编写好的代码 (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
}
}
错误信息:
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] ...
所以根据错误消息,它似乎在尝试查找导出的 excel 文件?这部分完全让我失望。任何帮助将不胜感激。 我在下面添加了我如何调用该方法,也许我在做一些愚蠢的事情。如果您可以推荐的话,我也准备使用其他方法来提取我的 zip 文件。
val tempDirectoryDir = "src/test/resources/oepTemp/"
ZipArchive.unZip(tempDirectoryDir + "Sub Region Input - Output.zip", tempDirectoryDir)
既然我们正在使用 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)
}
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
}
}
这是一种更实用、更精确的方法
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, _))
}
尝试使用 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, _))
}
}
}
来晚了,但我会利用 scala.collection.JavaConverters
在 zip 文件条目上获得 for-loop,并利用 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)
}
}
}
我会将 ZipFile.close() 的自动调用合并到史蒂夫的答案中。它是通过 Noel Yap 的回答中提供的 using 方法制作的。
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)
}
}
}
}