需要帮助使用 Clojure 下载和读取内存中的压缩 CSV 文件

Need help downloading and reading a zipped CSV file in memory with Clojure

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

帮助我继续前进。我尝试使用那里链接的第一个选项 (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. 在上面的代码中,我必须调用这个 .getNextEntry,否则我会得到一个空列表。作为一个正在努力编写功能代码的人,这让我很困扰,因为据我所知,我在这里处理状态——我的流对象看起来是可变的,这是我真的不想要的。有没有一种方法可以绕过这一步并且直接没有它?

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

我是 Clojure 的新手,一般来说我对 Java 一无所知,因此,如您所见,我对这些流对象的了解非常有限。我试图在 Java 中阅读有关它的一些内容,但我放弃了,因为我不确定其中有多少对学习 Clojure 的人有用,所以任何指针也很感激。

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

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

  2. 我没怎么玩过ZipInputStream,但如果觉得需要用.getNextEntry(),就用吧。

  3. read-csv 的示例显示使用 Reader 来访问输入文件,因此这是预期的行为。

  4. This template project 展示了我喜欢如何组织 Clojure 项目和源代码。请务必仔细阅读所提供的文档列表。

  5. 别忘了utilize cljdoc.org for looking up Clojure library API docs. For example, see the API docs for data.csv


更新

您可能还想查看

使用https://github.com/techascent/tech.ml.dataset optionally with https://scicloj.github.io/tablecloth/index.html(TMD 类似api 的dplyr)

还具有速度极快的优势,能够处理无法放入内存的数据集,会谈 SQL、Arrow 等。阿尔。在这里加入关于它的对话: https://clojurians.zulipchat.com/#narrow/stream/151924-data-science/topic/tech.2Eml.2Edataset