Как мне заархивировать несколько файлов в файл .zip с помощью scala? - PullRequest
14 голосов
/ 03 апреля 2012

Может ли кто-нибудь опубликовать простой фрагмент, который делает это?

Файлы - это текстовые файлы, поэтому лучше использовать сжатие, чем архивировать файлы.

У меня есть имена файлов, хранящиеся в итерируемом.

Ответы [ 6 ]

21 голосов
/ 03 апреля 2012

В настоящее время нет способа сделать что-то подобное из стандартной библиотеки 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()
}

Я сосредотачиваюсь на простоте, а не на эффективности (никакие проверки ошибок, чтение и запись по одному байту за раз не идеальны), но это работает и может быть легко улучшено.

7 голосов
/ 11 августа 2016

Мне недавно тоже пришлось работать с zip-файлами, и я нашел эту очень полезную утилиту: https://github.com/zeroturnaround/zt-zip

Вот пример архивирования всех файлов в каталоге:

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

Очень удобно.

3 голосов
/ 17 октября 2014

Ответ Трэвиса верен, но я немного подправил, чтобы получить более быструю версию его кода:

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()
}
3 голосов
/ 12 октября 2012

Это немного больше стиля 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
1 голос
/ 26 января 2017

Немного модифицированная (укороченная) версия с использованием 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()
}
0 голосов
/ 11 июня 2018

Как предполагает Габриэле Петронелла, дополнительно необходимо добавить ниже зависимости maven в pom.xml и ниже импорта

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