Это похоже на ответ Скуро, который использует ZipInputStream
, но немного более краткое определение entries
.
(defn entries [zip-stream]
(take-while #(not (nil? %))
(repeatedly #(.getNextEntry zip-stream))))
(defn walkzip [fileName]
(with-open [z (ZipInputStream. (FileInputStream. fileName))]
(doseq [e (entries z)]
(println (.getName e))
(.closeEntry z))))
Или, если вы действительно хотите извлечь файлы, вам нужна другая вспомогательная функция для копирования. Я использовал clojure.java.io
для сокращения кода, но то же самое можно сделать без этой зависимости.
(require '[clojure.java.io :as io])
(defn entries [zip-stream]
(take-while #(not (nil? %))
(repeatedly #(.getNextEntry zip-stream))))
(defn copy-file [zip-stream filename]
(with-open [out-file (file-out-stream filename)]
(let [buff-size 4096
buffer (byte-array buff-size)]
(loop [len (.read zip-stream buffer)]
(when (> len 0)
(.write out-file buffer 0 len)
(recur (.read zip-stream buffer)))))))
(defn extract-stream [zip-stream to-folder]
(let [extract-entry (fn [zip-entry]
(when (not (.isDirectory zip-entry))
(let [to-file (io/file to-folder
(.getName zip-entry))
parent-file (io/file (.getParent to-file))]
(.mkdirs parent-file)
(copy-file zip-stream to-file))))]
(->> zip-stream
entries
(map extract-entry)
dorun)))
Это фактически эквивалентно простому разархивированию файла с помощью утилиты unzip
. Прелесть этого в том, что, поскольку записи в ленивом порядке, вы можете filter
или drop
или take
для вашего сердца (или требования) контента. Ну, я уверен, что вы можете. Еще не пробовал:)
Также обратите внимание. Вы ДОЛЖНЫ обработать последовательность внутри функции, в которой вы открываете поток zip !!!