Как распаковать файл на диске в каталог с помощью Clojure? - PullRequest
0 голосов
/ 28 января 2020

Есть ли простой способ разархивировать файл на диске в каталог с помощью Clojure? Все, что я нашел, - это разархивирование одного файла, но у меня есть несколько почтовых индексов. Я хочу распаковать его, а затем прочитать указанный c в память. Попытка создать инструмент ETL, который загружает zip-файл, распаковывает его, читает указанный файл c в память, а затем делает что-то с ним. В идеале я мог бы использовать .getNextEntry или что-то подобное и читать в память, когда это соответствует регулярному выражению

1 Ответ

0 голосов
/ 28 января 2020

Я обнаружил, что разархивировать содержимое файла на удивление сложно в Clojure или Java, потому что вы должны сами создать структуру каталогов. Я могу представить, что есть готовые библиотеки, но я однажды использовал что-то вроде следующего:

;; in project.clj or build.boot add dependency
;; [org.apache.commons/commons-compress "1.3"] 

(ns com.example.my.namespace
  (:require 
    [clojure.java.io :as io]
    [clojure.tools.logging :as log])
  (:import
    [org.apache.commons.compress.archivers.zip ZipFile ZipArchiveEntry]))

;; Note that make-parents is called for every file. Tested with ZIP
;; with ca 80k files. Not significantly slower than testing here for
;; .isDirectory and only then create the parents. Keeping the nicer
;; code with this comment, then.
(defn- unzip-file [zip-file to-dir]
  (log/infof "Extracting %s" zip-file)
  (log/debug "  to:" to-dir)
  (with-open [zipf (ZipFile. (io/file zip-file))]
    (doseq [entry (enumeration-seq (.getEntries zipf))
            :when (not (.isDirectory ^ZipArchiveEntry entry))
            :let  [zip-in-s (.getInputStream zipf entry)
                   out-file (io/file (str to-dir
                                          java.io.File/separator
                                          (.getName entry)))]]
      (log/trace "  ->" (.getName out-file))
      (io/make-parents out-file)
      (with-open [entry-o-s (io/output-stream out-file)]
        (io/copy zip-in-s entry-o-s)))))

Повторные вызовы io/make-parents не имели значения в моих тестах.

Я не уверен, действительно ли это то, что вы хотите использовать. Просто чтение одного файла из Zip, вероятно, будет сделано без извлечения всего остального. Я все же перебираю содержимое zip-файла таким же образом. Только не создавайте выходную структуру и вместо использования io/copy для потоковой передачи содержимого из zip-файла в другой файл на dis c slurp из входного потока.

...