简体   繁体   中英

How to zip a folder recursively with Clojure

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.

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)))

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

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

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))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM