首页 > 解决方案 > 需要帮助使用 Clojure 下载和读取内存中的压缩 CSV 文件

问题描述

我有一个外部站点,我想从中下载压缩的 CSV 文件。目前,我正在下载它解压缩,将其保存到磁盘,然后解压缩,将解压缩的文件保存到磁盘,然后使用 CSV 阅读器读取解压缩的文件。这个过程中很多无用的步骤可以被删掉,我继续这样做。

这个惊人的答案帮助我让自己前进。我尝试使用那里链接的第一个选项 ( GZIPInputStream),但我收到“非 GZIP 格式”错误,所以我想我必须转到第二个选项。

这是我当前的代码,它做我想做的事:

(defn download-zipped-stream!
  (:body (clj-http.client/get "www.example.com" {:as :stream})))

(with-open
  [stream (ZipInputStream. download-zipped-stream!)]
  (.getNextEntry stream)
  (doall (clojure.data.csv/read-csv (clojure.java.io/reader stream) :separator \;)))

我确实通过反复试验得到了这个。关于这段代码,我主要想改变/理解三件事。

  1. 理想情况下,我想将我的代码分成两部分:一是下载和解压缩内容,然后返回一个流 - 原因是我想稍后决定是直接将其作为 csv 读取,还是写入磁盘(我不想失去这个选项,因为在开发过程中,阅读预下载的 csv 文件比每次下载大内容要容易得多)。事实证明,如果我尝试在with-open调用之外访问流,我会收到“流关闭”错误(据我了解,这是完全有道理的)。

  2. 在上面的代码中,我必须调用 this .getNextEntry,否则我会得到一个空列表。作为一个努力编写函数式代码的人,这让我很困扰,因为据我所知,我在这里处理的是状态——我的流对象看起来是可变的,这是我真的不想要的。有没有办法解决这个步骤并且直接没有它?

  3. 我试图read-csv直接在stream对象上调用该方法,但read-csv显然并不知道如何处理 ZipInputStreams。看到这一点,我简单而希望地io/reader在两者之间打了一个电话,它奏效了。不过,我不知道这是否是最好的方法。这是正确的吗?

我对 Clojure 很陌生,而且我对 Java 完全一无所知,因此,正如您所看到的,我对这些流对象的了解非常有限。我尝试在 Java 中阅读有关它的一些内容,但我退出了,因为我不确定其中有多少对学习 Clojure 的人有用,因此也感谢任何指针。

标签: csvclojure

解决方案


我认为你的方法是正确的。建议考虑:

  1. 考虑使用wget手动将*.csv.gz文件下载到本地磁盘。然后,只需打开该本地文件,而不是使用clj-http.client/get.

  2. 我没有玩太多ZipInputStream,但如果.getNextEntry()似乎需要使用,那就去吧。

  3. The examples for read-csv show using a Reader to give access to the input file, so this is the expected behavior.

  4. This template project shows how I like to organize a Clojure project & source code. Be sure to peruse the list of documentation provided.

  5. Don't forget to utilize cljdoc.org for looking up Clojure library API docs. For example, see the API docs for data.csv.


Update

You may also want to review this answer.


推荐阅读