Last active
September 25, 2015 15:44
-
-
Save rtfpessoa/0c2729538e4836b6436a to your computer and use it in GitHub Desktop.
Zip Utils Scala Wrapper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.zip.{ZipEntry, ZipFile, ZipOutputStream} | |
import better.files._ | |
import scala.collection.JavaConversions.enumerationAsScalaIterator | |
import scala.language.existentials | |
import scala.util.{Properties, Try} | |
object ZipUtils { | |
def zip(basePath: File): Try[File] = { | |
val zipFile = File.newTemp(basePath.nameWithoutExtension, ".zip") | |
val zipEntries = basePath match { | |
case directory if directory.isDirectory => | |
directory.listRecursively() | |
.filter(_.fullPath != directory.fullPath) | |
.collect { | |
case file if file.isDirectory => | |
val relativeDirPath = directory.path.relativize(file.path).toString | |
// make sure it ends with / for ZipEntry to consider it a directory | |
val cleanRelativeDirPath = relativeDirPath.stripPrefix("/").stripSuffix("/") | |
val zipRelativeDirPath = s"$cleanRelativeDirPath/" | |
(file, new ZipEntry(zipRelativeDirPath)) | |
case file => | |
(file, new ZipEntry(directory.path.relativize(file.path).toString)) | |
} | |
case file => | |
val relativePath = file.parent.path.relativize(file.path).toString | |
List((file, new ZipEntry(relativePath))) | |
} | |
Try { | |
val zipOutputStream = new ZipOutputStream(zipFile.out) | |
zipEntries.foreach { | |
case (file, entry) if file.isDirectory => | |
zipOutputStream.putNextEntry(entry) | |
zipOutputStream.closeEntry() | |
case (file, entry) => | |
zipOutputStream.putNextEntry(entry) | |
zipOutputStream.write(file.bytes.toArray) | |
zipOutputStream.closeEntry() | |
} | |
zipOutputStream.close() | |
zipFile | |
} | |
} | |
def unzip(zipFile: File): Try[File] = { | |
val outputDir = File.newTempDir(zipFile.nameWithoutExtension) | |
Try { | |
val zipArchive = new ZipFile(zipFile.toJava) | |
val (directories, files) = enumerationAsScalaIterator(zipArchive.entries()).partition(_.isDirectory) | |
// process directories first to avoid failing file creation | |
directories.foreach { dir => | |
Try { | |
outputDir / dir.getName mkdirs() | |
} | |
} | |
files.foreach { file => | |
Try { | |
val fileStream = zipArchive.getInputStream(file) | |
val fileContent = fileStream.lines.mkString(Properties.lineSeparator) | |
outputDir / file.getName write fileContent | |
} | |
} | |
outputDir | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import better.files.File | |
import org.specs2.mutable._ | |
class ZipUtilsSpec extends Specification { | |
// Set sequential execution | |
sequential | |
case class TestFile(name: String, content: Option[String]) | |
val files = Seq( | |
TestFile("file1.json", Some( """{"field1":"valueA","field2":"valueB"}""")), | |
TestFile("file2.json", Some( """{"field1":"valueA","field2":"valueB"}""")), | |
TestFile("subDir", None), | |
TestFile("subDir/file3.json", Some( """{"field1":"valueA","field2":"valueB"}""")), | |
TestFile("emptySubDir", None) | |
) | |
"ZipUtils" should { | |
"zip and unzip" in { | |
val zipDir = File.newTempDir("zip-files") | |
files.foreach { | |
case TestFile(name, Some(content)) => | |
zipDir / name write content | |
case TestFile(name, None) => | |
zipDir / name mkdirs() | |
} | |
ZipUtils.zip(zipDir).map { zipFile => | |
ZipUtils.unzip(zipFile).map { outputDir => | |
val extractedFiles = outputDir.listRecursively() | |
.filter(_.fullPath != outputDir.fullPath) | |
.collect { | |
case file if file.isRegularFile => | |
val relativeName = outputDir.path.relativize(file.path).toString | |
val content = file.contentAsString | |
TestFile(relativeName, Some(content)) | |
case file if file.isDirectory => | |
val relativeName = outputDir.path.relativize(file.path).toString | |
TestFile(relativeName, None) | |
}.toSeq | |
extractedFiles must containTheSameElementsAs(files) | |
}.getOrElse(ko("Failed to unzip")) | |
}.getOrElse(ko("Failed to zip")) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment