2012-04-03 49 views

回答

16

這裏沒有目前沒有辦法做這樣的從標準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() 
} 

我專注於簡單性而不是效率這裏(沒有錯誤檢查並且一次讀寫一個字節並不理想),但它可以工作,並且可以很容易地進行改進。

+0

你應該'in.close()'當你與'in'完成。 – leedm777 2012-04-03 18:24:20

+0

當然,我現在已經修好了。 – 2012-04-03 18:30:04

+0

我知道它沒有優化,但不需要將字節包裝在一個數組中。你可以簡單地使用'zip.write(b)'。 – leedm777 2012-04-03 19:06:48

3

這是多一點點的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 
+0

'readByte(in).takeWhile(_> -1).toList'將在讀取大文件時消耗大量內存。使用'Iterator'可能會更好。 – jilen 2014-04-05 10:29:44

+0

'def readByte(bufferedReader:BufferedReader)= Stream.continually(bufferedReader.read())' – nafg 2014-12-16 07:59:05

3

的特拉維斯的答案是正確的,但我已經調整了很少得到他的代碼更快的版本:

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() 
} 
5

我最近不得不使用zip文件過,發現這個非常好的工具:https://github.com/zeroturnaround/zt-zip

這裏荏苒一個目錄下的所有文件的一個例子:

import org.zeroturnaround.zip.ZipUtil 
ZipUtil.pack(new File("/tmp/demo"), new File("/tmp/demo.zip")) 

非常方便。

1

有點修改使用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() 
}