Reputation: 48958
I would like to zip a folder recursevely with clojure. An example of such a folder would be
├── a
├── b
│ ├── c
│ │ └── ccc.txt
│ └── bb.txt
├── c
├── a.txt
└── b.txt
Option 1 : using the OS from within Clojure
What works with zip
in Ubuntu is to execute following in the root of this structure :
zip -r result.zip *
But you have to be in the working dir in order to do this. Using absolute paths will yield other results and omiting paths all together will flatten the structure of course.
Problem is that you cannot change the working directory in Clojure, not that I'm aware of that is..
Option 2 : using native Clojure (or Java)
This should be possible, and I find some zip implementations in Clojure or Java wrappers. Most of them however for single files.
This might be a solution : http://www.java-forums.org/blogs/java-io/973-how-work-zip-files-java.html
but before I try that out I'd like to now or there isn't a good Clojure library around.
Upvotes: 3
Views: 1330
Reputation: 21
You can use rtcritical/clj-ant-tasks library that wraps Apache Ant, and zip/unzip in a single line of code.
Add library dependency [rtcritical/clj-ant-tasks "1.0.1"]
(require '[rtcritical.clj-ant-tasks :refer [run-ant-task])
To zip a directory:
(run-ant-task :zip {:destfile "/tmp/archive.zip" :basedir "/tmp/archive"})
Zip a directory, where the base directory is included in the archive:
(run-ant-task :zip {:destfile "/tmp/archive.zip"
:basedir "/tmp"
:includes "archive/**"})
Note: run-ant-task(s) functions in this library namespace can be used to run any other Apache Ant task(s) as well.
For more information, see https://github.com/rtcritical/clj-ant-tasks
Upvotes: 2
Reputation: 18005
Based on @Kyle answer:
(require '[clojure.java.io :as io])
(import '[java.util.zip ZipEntry ZipOutputStream])
(defn zip-folder
"p input path, z output zip"
[p z]
(with-open [zip (ZipOutputStream. (io/output-stream z))]
(doseq [f (file-seq (io/file p)) :when (.isFile f)]
(.putNextEntry zip (ZipEntry. (str/replace-first (.getPath f) p "") ))
(io/copy f zip)
(.closeEntry zip)))
(io/file z))
Upvotes: 0
Reputation: 22258
What about something like this using clojure.core/file-seq
(require '[clojure.java.io :as io])
(import '[java.util.zip ZipEntry ZipOutputStream])
(with-open [zip (ZipOutputStream. (io/output-stream "foo.zip"))]
(doseq [f (file-seq (io/file "/path/to/directory")) :when (.isFile f)]
(.putNextEntry zip (ZipEntry. (.getPath f)))
(io/copy f zip)
(.closeEntry zip)))
Upvotes: 8
Reputation: 8286
Check https://github.com/AeroNotix/swindon A nice little wrapper around java.util.zip. using streams and https://github.com/chmllr/zeus a Simple Clojure library for zip-based compression
Upvotes: 0