【发布时间】:2012-04-16 15:49:56
【问题描述】:
谁能发布一个简单的sn-p来做到这一点?
文件是文本文件,因此压缩比仅仅归档文件更好。
我将文件名存储在一个可迭代对象中。
【问题讨论】:
谁能发布一个简单的sn-p来做到这一点?
文件是文本文件,因此压缩比仅仅归档文件更好。
我将文件名存储在一个可迭代对象中。
【问题讨论】:
目前没有任何方法可以从标准 Scala 库中执行此类操作,但使用起来非常容易java.util.zip:
def zip(out: String, files: Iterable[String]) = {
import java.io.{ BufferedInputStream, FileInputStream, FileOutputStream }
import java.util.zip.{ ZipEntry, ZipOutputStream }
val zip = new ZipOutputStream(new FileOutputStream(out))
files.foreach { name =>
zip.putNextEntry(new ZipEntry(name))
val in = new BufferedInputStream(new FileInputStream(name))
var b = in.read()
while (b > -1) {
zip.write(b)
b = in.read()
}
in.close()
zip.closeEntry()
}
zip.close()
}
我在这里关注的是简单性而不是效率(没有错误检查和一次读取和写入一个字节并不理想),但它可以工作,并且可以很容易地改进。
【讨论】:
zip.write(b)。
finally 块中关闭in 和zip。
Stream.continually(in.read()).takeWhile(_ > -1).foreach { b => zip.write(b) }
我最近也不得不使用 zip 文件,发现这个非常好的实用程序:https://github.com/zeroturnaround/zt-zip
这是一个将所有文件压缩到目录中的示例:
import org.zeroturnaround.zip.ZipUtil
ZipUtil.pack(new File("/tmp/demo"), new File("/tmp/demo.zip"))
非常方便。
【讨论】:
如果你喜欢功能性,这有点 scala 风格:
def compress(zipFilepath: String, files: List[File]) {
def readByte(bufferedReader: BufferedReader): Stream[Int] = {
bufferedReader.read() #:: readByte(bufferedReader)
}
val zip = new ZipOutputStream(new FileOutputStream(zipFilepath))
try {
for (file <- files) {
//add zip entry to output stream
zip.putNextEntry(new ZipEntry(file.getName))
val in = Source.fromFile(file.getCanonicalPath).bufferedReader()
try {
readByte(in).takeWhile(_ > -1).toList.foreach(zip.write(_))
}
finally {
in.close()
}
zip.closeEntry()
}
}
finally {
zip.close()
}
}
别忘了导入:
import java.io.{BufferedReader, FileOutputStream, File}
import java.util.zip.{ZipEntry, ZipOutputStream}
import io.Source
【讨论】:
readByte(in).takeWhile(_ > -1).toList 在读取大文件时会消耗大量内存。使用Iterator 可能会更好。
def readByte(bufferedReader: BufferedReader) = Stream.continually(bufferedReader.read())
Travis 的答案是正确的,但我稍作调整以获得他的代码的更快版本:
val Buffer = 2 * 1024
def zip(out: String, files: Iterable[String], retainPathInfo: Boolean = true) = {
var data = new Array[Byte](Buffer)
val zip = new ZipOutputStream(new FileOutputStream(out))
files.foreach { name =>
if (!retainPathInfo)
zip.putNextEntry(new ZipEntry(name.splitAt(name.lastIndexOf(File.separatorChar) + 1)._2))
else
zip.putNextEntry(new ZipEntry(name))
val in = new BufferedInputStream(new FileInputStream(name), Buffer)
var b = in.read(data, 0, Buffer)
while (b != -1) {
zip.write(data, 0, b)
b = in.read(data, 0, Buffer)
}
in.close()
zip.closeEntry()
}
zip.close()
}
【讨论】:
使用 NIO2 的稍微修改(更短)的版本:
private def zip(out: Path, files: Iterable[Path]) = {
val zip = new ZipOutputStream(Files.newOutputStream(out))
files.foreach { file =>
zip.putNextEntry(new ZipEntry(file.toString))
Files.copy(file, zip)
zip.closeEntry()
}
zip.close()
}
【讨论】:
根据 Gabriele Petronella 的建议,此外,您需要在 pom.xml 中添加以下 Maven 依赖项,以及以下导入:
import org.zeroturnaround.zip.ZipUtil
import java.io.File
<dependency>
<groupId>org.zeroturnaround</groupId>
<artifactId>zt-zip</artifactId>
<version>1.13</version>
<type>jar</type>
</dependency>*
【讨论】: