使用clojure中的java api读取zip文件

Dfr*_*Dfr 8 java clojure

我正试图在clojure中重写以下片段,但这一切都很难看,也许有人会建议一个更优雅的解决方案?

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class ZipFileRdrExp {

  public static void main(String[] args) {

    try {

      FileInputStream fis = new FileInputStream("C:\\MyZip.zip");
      ZipInputStream zis = new ZipInputStream(fis);
      ZipEntry ze;
      while((ze=zis.getNextEntry())!=null){
        System.out.println(ze.getName());
        zis.closeEntry();
      }

      zis.close();

    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这是我对getNextEntry重复调用的丑陋尝试:

(ns app.core
  (:import
  (java.io FileInputStream FileNotFoundException IOException File)
  (java.util.zip ZipInputStream ZipEntry)))


(defn- read-zip [zip-file]
  (let [fis (FileInputStream. zip-file)
        zis (ZipInputStream. fis)]
    (loop [ze (.getNextEntry zis)]
      (when ze
        (println (.getName ze))
        (.closeEntry zis)
        (recur (.getNextEntry zis))))
    (.close zis)))
Run Code Online (Sandbox Code Playgroud)

sku*_*uro 17

我会选择以下内容:

(defn entries [zipfile]
 (lazy-seq
  (if-let [entry (.getNextEntry zipfile)]
   (cons entry (entries zipfile)))))

(defn walkzip [fileName]
 (with-open [z (ZipInputStream. (FileInputStream. fileName))]
  (doseq [e (entries z)]
   (println (.getName e))
   (.closeEntry z))))
Run Code Online (Sandbox Code Playgroud)

编辑:上述代码最终经过测试和更正.

编辑:以下工作按预期工作,它更简洁,即使它使用不同的Java API

(defn entries [zipfile]
  (enumeration-seq (.entries zipfile)))

(defn walkzip [fileName]
  (with-open [z (java.util.zip.ZipFile. fileName)]
             (doseq [e (entries z)]
                    (println (.getName e)))))
Run Code Online (Sandbox Code Playgroud)

  • 注意:如果返回`entries`而不是立即消耗,`with-open`将与延迟评估冲突并在读取完成之前关闭输入流,从而触发异常. (3认同)

abe*_*dra 6

这是一个更简单的例子:

(defn filenames-in-zip [filename]
  (let [z (java.util.zip.ZipFile. filename)] 
    (map #(.getName %) (enumeration-seq (.entries z)))))
Run Code Online (Sandbox Code Playgroud)

这与上面的代码类似,但没有理由在这里使用with-open.此示例返回一系列数据,然后您可以打印出来或更好地格式化.最好让提取数据的函数只返回数据,而不是在该函数中包含打印的副作用.

如果要打印出内容,可以使用

(pprint (filenames-in-zip "my.zip"))
Run Code Online (Sandbox Code Playgroud)

它会给你一个很好的清单.

  • 虽然您不需要直接关闭ZipFile,但[强烈建议](http://download.oracle.com/javase/6/docs/api/java/util/zip/ZipFile.html#finalize())这样做是为了在您不再需要它们时立即释放资源. (2认同)