【问题标题】:How to download a file and unzip it from memory in clojure?如何在clojure中下载文件并将其从内存中解压缩?
【发布时间】:2015-09-23 14:47:17
【问题描述】:

我正在使用 clj-http 发出 GET 请求,响应是一个 zip 文件。此 zip 的内容始终是一个 CSV 文件。我想将 CSV 文件保存到磁盘,但我不知道如何。

如果我在磁盘上有文件,Raynes/fs 库中的(fs/unzip filename destination) 效果很好,但我不知道如何将 clj-http 的响应强制转换为可以读取的内容。如果可能的话,我想直接解压文件而不用

我得到的最接近(如果这更接近的话)将我带到一个 BufferedInputStream,但我从那里迷路了。

(require '[clj-http.client :as client])
(require '[clojure.java.io :as io])

(->
  (client/get "http://localhost:8000/blah.zip" {:as :byte-array})
  (:body)
  (io/input-stream))

【问题讨论】:

    标签: clojure


    【解决方案1】:

    您可以使用纯java java.util.zip.ZipInputStreamjava.util.zip.GZIPInputStream。取决于内容的压缩方式。这是使用 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")))
    

    使用 java.util.zip.ZipInputStream 只会稍微复杂一点:

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

    【讨论】:

    • 如果有人好奇,您在流上调用 .getNextEntry 之后,您可以针对流调用函数来获取第一个文件的内容。例如,如果文件是 CSV 或 JSON,您可以执行 (slurp stream) 来获取字符串,而不是上面示例中的最后一行(io/copy 流路径)。
    • 由于您使用的是clj-http,因此您也可以跳过一步并将正文作为流而不是字节数组返回:(http/get url {:as :stream})
    【解决方案2】:
    (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))))))))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-02-27
      • 2011-11-15
      • 2016-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-15
      相关资源
      最近更新 更多