How to download a file and unzip it from memory in clojure?

(require '[clj-http.client :as httpc])
(import '[java.io File])


(defn download-unzip [url dir]
  (let [saveDir (File. dir)]
    (with-open [stream (-> (httpc/get url {:as :stream})
                           (:body)
                           (java.util.zip.ZipInputStream.))]
      (loop [entry (.getNextEntry stream)]
        (if entry
          (let [savePath (str dir File/separatorChar (.getName entry))
                saveFile (File. savePath)]
            (if (.isDirectory entry)
              (if-not (.exists saveFile)
                (.mkdirs saveFile))
              (let [parentDir (File. (.substring savePath 0 (.lastIndexOf savePath (int File/separatorChar))))]
                (if-not (.exists parentDir) (.mkdirs parentDir))
                (clojure.java.io/copy stream saveFile)))
            (recur (.getNextEntry stream))))))))

You can use the pure java java.util.zip.ZipInputStream or java.util.zip.GZIPInputStream. Depends how the content is zipped. This is the code that saves your file using java.util.zip.GZIPInputStream :

(->
  (client/get "http://localhost:8000/blah.zip" {:as :byte-array})
  (:body)
  (io/input-stream)
  (java.util.zip.GZIPInputStream.)
  (clojure.java.io/copy (clojure.java.io/file "/path/to/output/file")))

Using java.util.zip.ZipInputStream makes it only a bit more complicated :

(let [stream (->
                (client/get "http://localhost:8000/blah.zip" {:as :byte-array})
                (:body)
                (io/input-stream)
                (java.util.zip.ZipInputStream.))]
      (.getNextEntry stream)
      (clojure.java.io/copy stream (clojure.java.io/file "/path/to/output/file")))

Tags:

Clojure