Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

writing zip file to file in Clojure

Tags:

clojure

I have a method for zipping:

    (defn zip-project [project-id notebooks files]
  (with-open [out (ByteArrayOutputStream.)
              zip (ZipOutputStream. out)]
    (doseq [nb notebooks]
      (.putNextEntry zip (ZipEntry. (str "Notebooks/" (:notebook/name nb) ".bkr")))
      (let [nb-json (:notebook/contents nb)
            bytes (.getBytes nb-json)]
        (.write zip bytes))
      (.closeEntry zip))
    (doseq [{:keys [name content]} files]
      (.putNextEntry zip (ZipEntry. (str "Files/" name)))
      (io/copy content zip)
      (.closeEntry zip))
    (.finish zip)
    (.toByteArray out)))

after I make a zip I want to save it into the file something like /tmp/sample/sample.zip, but I cannot seem to make it. here is what I am doing:

(defn create-file! [path zip]
  (let [f (io/file path)]
    (io/make-parents f)
    (io/copy zip f)
    true))

The problem is, when I run unzip from terminal it says that zip file is empty and if I unzip it using Archive utility it extracts with cpgz extension.

What am I doing wrong here?

like image 886
fishera Avatar asked Sep 28 '16 18:09

fishera


1 Answers

You will need essentially 4 things

  1. Import everything (normally you would use (ns ...) but you can run this in the repl

    (import 'java.io.FileOutputStream)
    (import 'java.io.BufferedOutputStream)
    (import 'java.io.ZipOutputStream)
    (import 'java.util.zip.ZipOutputStream)
    (import 'java.util.zip.ZipEntry)
    
  2. You need a way to initialize the stream. This can be done nicely with the -> macro:

    (defn zip-stream
      "Opens a ZipOutputStream over the given file (as a string)"
      [file]
      (-> (FileOutputStream. file)
          BufferedOutputStream.
          ZipOutputStream.))
    
  3. You need a way to create/close entries in the ZipOutputStream

    (defn create-zip-entry
      "Create a zip entry with the given name. That will be the name of the file inside the zipped file."
      [stream entry-name]
      (.putNextEntry stream (ZipEntry. entry-name)))
    
  4. Finally you need a way to write your content.

    (defn write-to-zip
      "Writes a string to a zip stream as created by zip-stream"
      [stream str]
      (.write stream (.getBytes str)))
    
  5. Putting it all together:

    (with-open [stream (zip-stream "coolio.zip")]
      (create-zip-entry stream "foo1.txt")
      (write-to-zip stream "Hello Foo1")
      (.closeEntry stream) ;; don't forget to close entries
      (create-zip-entry stream "foo2.txt")
      (write-to-zip stream "Hello Foo 2")
      (.closeEntry stream))
    
  6. The result:

The result

like image 99
fernandohur Avatar answered Sep 28 '22 08:09

fernandohur