class Zipper extends AnyRef
Zipper: Write zip and jar files more easily
The Zipper class provides a convenient mechanism for writing zip and jar
files; it's a simplifying layer that sits on top of the existing Zip and
Jar classes provided by the JDK. A Zipper object behaves somewhat like an
immutable Scala collection, into which you can drop File objects,
InputStream objects, Reader objects, Source objects, URLs and
pathnames. When you call writeZip or writeJar, the objects in Zipper
are written to the actual underlying zip or jar file.
A Zipper can either preserve pathnames or flatten the paths down to single
components. When preserving pathnames, a Zipper object converts absolute
paths to relative paths by stripping any leading "file system mount points."
On Unix-like systems, this means stripping the leading "/"; on Windows, it
means stripping any leading drive letter and the leading "\". (See
java.io.File.listRoots() for more information.) For instance, if you're not
flattening pathnames, and you add C:\Temp\hello.txt to a Zipper on
Windows, the Zipper will strip the C:\, adding Temp/hello.txt. to the
zip or jar file. If you're on a Unix-like system, including Mac OS X, and
you add /tmp/foo/bar.txt, the Zipper will add tmp/foo/bar.txt to the
file.
Directories
You can explicitly add directory entries to a Zipper, using
addZipDirectory(). When you're not flattening entries, a Zipper object will
also ensure that any intermediate directories in a pathname are created in
the zip file. For instance, if you add file /tmp/foo/bar/baz.txt to a
Zipper, without flattening it, the Zipper will create the following
entries in the underlying zip file:
tmp(directory)tmp/foo(directory)tmp/foo/bar(directory)tmp/foo/bar/baz.txt(the entry)
If you use the JDK's zip or jar classes directly, you have to create those
intermediate directory entries yourself. In addition, you have to be careful
not to create a directory more than once; doing so will cause an error.
Zipper automatically creating unique intermediate directories for you.
Constructing a Zipper object
The class constructor is private; use the companion object's apply()
functions to instantiate Zipper objects.
Using a Zipper object
The addFile() methods all return Try objects, and they do not modify
the original Zipper object. On success, they return a Success object
that contains a new Zipper.
Because the addFile() methods return Try, they are unsuitable for use
in traditional "builder" patterns. For instance, the following will not
work:
// Will NOT work val zipper = Zipper() zipper.addFile("/tmp/foo/bar.txt").addFile("/tmp/baz.txt")
There are other patterns you can use, however. Since Try is monadic, a
for comprehension works nicely:
val zipper = Zipper() val newZipper = for { z1 <- zipper.addFile("/tmp/foo/bar.txt") z2 <- z1.addFile("/tmp/baz.txt") z3 <- z2.addFile("hello.txt") } yield z3 // newZipper is a Try[Zipper]
If you're trying to add a collection of objects, a for comprehension
can be problematic. If you're not averse to using a local var, you
can just use a traditional imperative loop:
val zipper = Zipper() var z = zipper val paths: List[String] = ... for (path <- paths) { val t = z.addFile(path) z = t.get // will throw an exception if the add failed }
You can also avoid a var using foldLeft(), though you still have to
contend with a thrown exception. (You can always wrap the code in a Try.)
val zipper = Zipper() val paths: List[String] = ... paths.foldLeft(zipper) { case (z, path) => z.addFile(path).get // throws an exception if the add fails }
Finally, to avoid the exception and the var, use tail-recursion:
import scala.annnotation.tailrec import scala.util.{Failure, Success, Try} @tailrec def addNext(paths: List[String], currentZipper: Zipper): Try[Zipper] = { paths match { case Nil => Success(currentZipper) case path :: rest => // Can't use currentZipper.addFile(path).map(), because the recursion // will then be invoked within the lambda, violating tail-recursion. currentZipper.addFile(path) match { case Failure(ex) => Failure(ex) case Success(z) => addNext(rest, z) } } } val paths: List[String] = ... val zipper = addNext(paths, Zipper())
Notes
A Zipper is not a true Scala collection. It does not support extensively
querying its contents, looping over them, or transforming them. It is simply a
container to be filled and then written.
The Zipper class currently provides no support for storing uncompressed
(i.e., fully inflated) entries. All data stored in the underlying zip is
compressed, even though the JDK-supplied zip classes support both compressed
and uncompressed entries. If necessary, the Zipper class can be extended
to support storing uncompressed data.
- Alphabetic
- By Inheritance
- Zipper
- AnyRef
- Any
- Hide All
- Show All
- Public
- All
Value Members
-
final
def
!=(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
final
def
##(): Int
- Definition Classes
- AnyRef → Any
-
final
def
==(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
def
addBytes(bytes: Array[Byte], zipPath: String): Try[Zipper]
Add an array of bytes to the
Zipper.Add an array of bytes to the
Zipper. The bytes constitute an eventual entry in a zip file; a reference to the byte array is held within thisZipperuntil it is garbage-collected.- bytes
the array of bytes representing the entry to be written to the zip file
- zipPath
the path for the entry in the zip file
-
def
addDirectory(dir: File, strip: Option[String] = None, flatten: Boolean = false, wildcard: Option[String] = None): Try[Zipper]
Recursively add all the files in a directory to the
Zipper.Recursively add all the files in a directory to the
Zipper. Does not currently work properly on Windows.- dir
the directory, which must exist
- strip
optional leading path to strip. If not specified, the full path to each file (minus file system root) is used.
- flatten
whether or not to flatten the entries. Note that a
truevalue can cause errors if files in different directories have the same name.- wildcard
optional wildcard to match files against. If
None, all files found are added. This is a simple glob pattern, acceptable to grizzled.file.util.fnmatch.- returns
A
Successwith the newZipper, orFailureon error.
-
def
addFile(f: File, zipPath: String): Try[Zipper]
Add a file to the
Zipper, specifying the zip file entry name explicitly.Add a file to the
Zipper, specifying the zip file entry name explicitly.Note: The existence or non-existence of the file isn't checked until you call
writeZip()orwriteJar().- f
the
Fileto be added- zipPath
the path of the entry in the zip or jar file. Any file system root will be stripped.
- returns
A
Successwith a newZipperobject, on success. AFailureon error. The originalZipperis not modified.
-
def
addFile(f: File, flatten: Boolean): Try[Zipper]
Add a file to the
Zipper.Add a file to the
Zipper. The entry in the zip file will be the base name of the file, ifflattenis specified. Otherwise, it'll be the path itself (if the path is relative) or the path with the file system root removed (if it's absolute).Note: The existence or non-existence of the file isn't checked until you call
writeZip()orwriteJar().- f
the
Fileto be added- flatten
whether or not to flatten the path in the zip file
- returns
A
Successwith a newZipperobject, on success. AFailureon error. The originalZipperis not modified.
-
def
addFile(f: File): Try[Zipper]
Add a file to the
Zipper.Add a file to the
Zipper. The path in the resulting zip or jar file will be the path (if it's relative) or the path with the file system root removed (if it's absolute).Note: The existence or non-existence of the file isn't checked until you call
writeZip()orwriteJar().- f
the
Fileto be added- returns
A
Successwith a newZipperobject, on success. AFailureon error. The originalZipperis not modified.
-
def
addFile(path: String, zipPath: String): Try[Zipper]
Add a file to the
Zipper, specifying the zip file entry name explicitly.Add a file to the
Zipper, specifying the zip file entry name explicitly.Note: The existence or non-existence of the file isn't checked until you call
writeZip()orwriteJar().- path
path to the file to add
- zipPath
the path of the entry in the zip or jar file. Any file system root will be stripped.
- returns
A
Successwith a newZipperobject, on success. AFailureon error. The originalZipperis not modified.
-
def
addFile(path: String, flatten: Boolean): Try[Zipper]
Add a file to the
Zipper.Add a file to the
Zipper. The entry in the zip file will be the base name of the file, ifflattenis specified. Otherwise, it'll be the path itself (if the path is relative) or the path with the file system root removed (if it's absolute).Note: The existence or non-existence of the file isn't checked until you call
writeZip()orwriteJar().- path
path to the file to add
- flatten
whether or not to flatten the path in the zip file
- returns
A
Successwith a newZipperobject, on success. AFailureon error. The originalZipperis not modified.
-
def
addFile(path: String): Try[Zipper]
Add a file to the
Zipper.Add a file to the
Zipper. The path in the resulting zip or jar file will be the path (if it's relative) or the path with the file system root removed (if it's absolute).Note: The existence or non-existence of the file isn't checked until you call
writeZip()orwriteJar().- path
path to the file to add
- returns
A
Successwith a newZipperobject, on success. AFailureon error. The originalZipperis not modified.
-
def
addInputStream(inputStream: InputStream, zipPath: String, flatten: Boolean): Try[Zipper]
Add an
InputStreamto theZipper, using the specified path in the zip file.Add an
InputStreamto theZipper, using the specified path in the zip file. Ifflattenis specified, all directories will be removed from the zip path; otherwise, it will be used as-is, with any file system root removed.Warning: An
InputStreamrepresents an open resource (e.g., an open file descriptor). Those resources are held open until you callwriteZip()orwriteJar(). If you add too manyInputStreamobjects (orReaderorSourceobjects) to aZipper, you could theoretically, run out of open file descriptors.- inputStream
the
InputStreamto add- zipPath
the path to use within the zip file. Any file system root is removed from this path.
- flatten
whether or not to flatten the zip path
- returns
A
Successwith a newZipperobject, on success. AFailureon error. The originalZipperis not modified.
-
def
addInputStream(inputStream: InputStream, zipPath: String): Try[Zipper]
Add an
InputStreamto theZipper, using the specified path in the zip file.Add an
InputStreamto theZipper, using the specified path in the zip file.Warning: An
InputStreamrepresents an open resource (e.g., an open file descriptor). Those resources are held open until you callwriteZip()orwriteJar(). If you add too manyInputStreamobjects (orReaderorSourceobjects) to aZipper, you could theoretically, run out of open file descriptors.- inputStream
the
InputStreamto add- zipPath
the path to use within the zip file. Any file system root is removed from this path.
- returns
A
Successwith a newZipperobject, on success. AFailureon error. The originalZipperis not modified.
-
def
addReader(reader: Reader, zipPath: String, flatten: Boolean): Try[Zipper]
Add a
Readerto theZipper, using the specified path in the zip file.Add a
Readerto theZipper, using the specified path in the zip file. Ifflattenis specified, all directories will be removed from the zip path; otherwise, it will be used as-is, with any file system root removed.Warning: A
Readerrepresents an open resource (e.g., an open file descriptor). Those resources are held open until you callwriteZip()orwriteJar(). If you add too manyInputStreamobjects (orInputStreamorSourceobjects) to aZipper, you could theoretically, run out of open file descriptors.- reader
the
Readerto add- zipPath
the path to use within the zip file. Any file system root is removed from this path.
- flatten
whether or not to flatten the zip path
- returns
A
Successwith a newZipperobject, on success. AFailureon error. The originalZipperis not modified.
-
def
addReader(reader: Reader, zipPath: String): Try[Zipper]
Add a
Readerto theZipper, using the specified path in the zip file.Add a
Readerto theZipper, using the specified path in the zip file.Warning: A
Readerrepresents an open resource (e.g., an open file descriptor). Those resources are held open until you callwriteZip()orwriteJar(). If you add too manyInputStreamobjects (orInputStreamorSourceobjects) to aZipper, you could theoretically, run out of open file descriptors.- reader
the
Readerto add- zipPath
the path to use within the zip file. Any file system root is removed from this path.
- returns
A
Successwith a newZipperobject, on success. AFailureon error. The originalZipperis not modified.
-
def
addSource(source: Source, zipPath: String, flatten: Boolean): Try[Zipper]
Add a
scala.io.SOurceto theZipper, using the specified path in the zip file.Add a
scala.io.SOurceto theZipper, using the specified path in the zip file. Ifflattenis specified, all directories will be removed from the zip path; otherwise, it will be used as-is, with any file system root removed.Warning: A
Sourcerepresents an open resource (e.g., an open file descriptor). Those resources are held open until you callwriteZip()orwriteJar(). If you add too manySourceobjects (orReaderorInputStreamobjects) to aZipper, you could theoretically, run out of open file descriptors.- source
the
Sourceto add- zipPath
the path to use within the zip file. Any file system root is removed from this path.
- flatten
whether or not to flatten the zip path
- returns
A
Successwith a newZipperobject, on success. AFailureon error. The originalZipperis not modified.
-
def
addSource(source: Source, zipPath: String): Try[Zipper]
Add a
scala.io.Sourceto theZipper, using the specified path in the zip file.Add a
scala.io.Sourceto theZipper, using the specified path in the zip file.Warning: A
Sourcerepresents an open resource (e.g., an open file descriptor). Those resources are held open until you callwriteZip()orwriteJar(). If you add too manySourceobjects (orReaderorInputStreamobjects) to aZipper, you could theoretically, run out of open file descriptors.- source
the
Sourceto add- zipPath
the path to use within the zip file. Any file system root is removed from this path.
- returns
A
Successwith a newZipperobject, on success. AFailureon error. The originalZipperis not modified.
-
def
addURL(url: URL, zipPath: String): Try[Zipper]
Add a
grizzled.net.URLto theZipper.Add a
grizzled.net.URLto theZipper. This method is just shorthand for:val gurl = grizzled.net.URL(...) zipper.addURL(gurl.javaURL)- url
the URL to the resource to be added
- zipPath
the path within the zip file for the entry
- returns
A
Successwith a newZipperobject, on success. AFailureon error. The originalZipperis not modified.
-
def
addURL(url: URL, zipPath: String): Try[Zipper]
Add a
java.net.URLto theZipper.Add a
java.net.URLto theZipper. The path in the zip file will be taken from the path component of the URL. That means the URL must have a file name component. For instance, if you add the URLhttp://www.example.com/, you'll get an error, because the path component is "/", and the corresponding relative path is "". In other words,Zipperdoes not addindex.htmlfor you automatically. A URL likehttp://www.example.com/index.htmlwill work fine, resulting inindex.htmlbeing added to the resulting zip file. Similarly, using this method to addhttp://www.example.com/music/My-Song.mp3will writemusic/My-Song.mp3to the zip or jar file.Note: The URL is not validated (i.e., no connection is made) until you call
writeZip()orwriteJar().- url
the URL to the resource to be added
- zipPath
the path within the zip file for the entry
- returns
A
Successwith a newZipperobject, on success. AFailureon error. The originalZipperis not modified.
-
def
addZipDirectory(path: String): Try[Zipper]
Add a directory entry to the
Zipper.Add a directory entry to the
Zipper. The path should be in "/" form, even on Windows, since zip and jar files always use "/". Any leading "/" will be removed, converting it to a relative path.- path
the path of the directory entry to add
- returns
A
Successwith a newZipperobject, on success. AFailureon error. The originalZipperis not modified.
-
final
def
asInstanceOf[T0]: T0
- Definition Classes
- Any
-
def
clone(): AnyRef
- Attributes
- protected[java.lang]
- Definition Classes
- AnyRef
- Annotations
- @native() @throws( ... )
- val comment: Option[String]
-
final
def
eq(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
-
def
equals(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
def
finalize(): Unit
- Attributes
- protected[java.lang]
- Definition Classes
- AnyRef
- Annotations
- @throws( classOf[java.lang.Throwable] )
-
final
def
getClass(): Class[_]
- Definition Classes
- AnyRef → Any
- Annotations
- @native()
-
def
hashCode(): Int
- Definition Classes
- AnyRef → Any
- Annotations
- @native()
-
final
def
isInstanceOf[T0]: Boolean
- Definition Classes
- Any
-
final
def
ne(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
-
final
def
notify(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native()
-
final
def
notifyAll(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native()
-
val
paths: Set[String]
The unique paths in the
Zipper.The unique paths in the
Zipper. The directory entries will be suffixed with "/". Note that intermediate directory entries will not be represented in this list. Only the paths that have been explicitly added are represented. -
def
setComment(comment: String): Zipper
Set the comment to be written to the zip or jar file.
Set the comment to be written to the zip or jar file.
- comment
the comment.
- returns
a new
Zipperwith the comment. This operation cannot fail, so the new value is returned without being wrapped in aTry.
-
final
def
synchronized[T0](arg0: ⇒ T0): T0
- Definition Classes
- AnyRef
-
def
toString(): String
- Definition Classes
- AnyRef → Any
-
final
def
wait(): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws( ... )
-
final
def
wait(arg0: Long, arg1: Int): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws( ... )
-
final
def
wait(arg0: Long): Unit
- Definition Classes
- AnyRef
- Annotations
- @native() @throws( ... )
-
def
writeJar(jarFile: File, manifest: Option[Manifest]): Try[File]
Write the contents of this
Zipperto a jar file, with or without a jar manifest.Write the contents of this
Zipperto a jar file, with or without a jar manifest. You can call this method more than once.Warning: While you can call this method multiple times (to write a single
Zipperto multiple zip files, for instance), some entry sources cannot be read multiple times. For instance,Zipperdoes not attempt to rewindReader,InputStreamorSourceobjects, so they cannot be read more than once; reusing aZippercontaining those types of sources will result in an error.- jarFile
the jar file to write. If it exists, it will be overwritten.
- manifest
optional jar manifest
- returns
A
Successcontaining thejarFileparameter, on success. AFailureon error.
-
def
writeJar(jarFile: File): Try[File]
Write the contents of this
Zipperto a jar file.Write the contents of this
Zipperto a jar file. The jar file will not have a jar manifest. You can call this method more than once.Warning: While you can call this method multiple times (to write a single
Zipperto multiple zip files, for instance), some entry sources cannot be read multiple times. For instance,Zipperdoes not attempt to rewindReader,InputStreamorSourceobjects, so they cannot be read more than once; reusing aZippercontaining those types of sources will result in an error.- jarFile
the jar file to write. If it exists, it will be overwritten.
- returns
A
Successcontaining thejarFileparameter, on success. AFailureon error.
-
def
writeJar(path: String): Try[File]
Write the contents of this
Zipperto a jar file.Write the contents of this
Zipperto a jar file. The jar file will not have a jar manifest. You can call this method more than once.Warning: While you can call this method multiple times (to write a single
Zipperto multiple zip files, for instance), some entry sources cannot be read multiple times. For instance,Zipperdoes not attempt to rewindReader,InputStreamorSourceobjects, so they cannot be read more than once; reusing aZippercontaining those types of sources will result in an error.- path
the path to the jar file to write. If it exists, it will be overwritten
- returns
A
Successwith aFileof the written jar, on success. AFailureon error.
-
def
writeZip(zipFile: File): Try[File]
Write the contents of this
Zipperto a zip file.Write the contents of this
Zipperto a zip file. You can call this method more than once.Warning: While you can call this method multiple times (to write a single
Zipperto multiple zip files, for instance), some entry sources cannot be read multiple times. For instance,Zipperdoes not attempt to rewindReader,InputStreamorSourceobjects, so they cannot be read more than once; reusing aZippercontaining those types of sources will result in an error.- zipFile
the zip file to write. If it exists, it will be overwritten.
- returns
A
Successcontaining thezipFileparameter, on success. AFailureon error.
-
def
writeZip(path: String): Try[File]
Write the contents of this
Zipperto a zip file.Write the contents of this
Zipperto a zip file. You can call this method more than once.Warning: While you can call this method multiple times (to write a single
Zipperto multiple zip files, for instance), some entry sources cannot be read multiple times. For instance,Zipperdoes not attempt to rewindReader,InputStreamorSourceobjects, so they cannot be read more than once; reusing aZippercontaining those types of sources will result in an error.- path
the path to the zip file to write. If it exists, it will be overwritten
- returns
A
Successwith aFileof the written zip, on success. AFailureon error.