【问题标题】:Opening file in the same directory as running code in Clojure在与 Clojure 中运行代码相同的目录中打开文件
【发布时间】:2013-04-09 00:23:58
【问题描述】:

我正在尝试用 Clojure 编写一些测试。其中一项测试涉及在与正在运行的测试文件相同的目录中打开一个 html 文件,以将其内容用作测试输入(Python 中广泛使用的习惯用法)。我认为*file* var 可以完成这项工作,但事实并非如此,因为它是相对的。

假设我的项目使用默认的 leiningen 布局,名为demoproj。然后我的测试在~/projects/demoproj/test。这个目录再次复制了项目命名空间,我不是很喜欢,但无论如何。所以core.clj 的测试在~/projects/demoproj/test/demoproj/test/core.clj 中。我在同一目录中还有一个名为small_page.html 的文件。如果我将以下内容放入test/core.clj:

(println (-> (java.io.File. *file*)
             .getPath))

这是我得到的:

demoproj/test/readibility.clj

这是相对于项目库的test 目录。我尝试仅使用此相对路径读取示例 html 页面,如下所示:

(slurp (-> (java.io.File. *file*)
            .getParent
            (java.io.File. "small_page.html")
            .getPath))

这会导致 IO 错误,因为无法在该位置读取文件。我的下一个想法是获取当前工作目录并将其与相对路径连接。这是我获取工作目录的方式:

(println (-> (java.io.File. ".")
             .getCanonicalPath))

返回绝对路径:

/Path-to-home/projects/demoproj

不好的是,这两个没有加入到文件的正确路径;中间缺少一个 test 组件。因此,将这两个路径连接起来会导致目录路径不正确。

那么,我的问题是,是否有可靠的方法来获取当前执行的代码文件的绝对路径?如果这是不可能的,那么这个习语的替代方法是什么,即我如何解析与测试文件相关的位置的文件?

【问题讨论】:

    标签: clojure


    【解决方案1】:

    因为 clojure 代码和相关资源最终可能会出现在 jar 中,并且您希望代码能够运行,即使您正在访问的文件最终会成为 jar 的一部分而不是真正的文件系统,这是可靠的方法这是使用 io/resource,并确保有问题的文件位于资源路径中。

    例如,我在当前项目中的目录结构中包含以下内容:

    |-- project.clj
    |-- resources
    |   |-- caribou.properties
    |   |-- config
    |   |   |-- boot.clj
    |   |   |-- development.clj
    |   |   |-- local-dumped.clj
    |   |   |-- local.clj
    |   |   |-- production.clj
    |   |   |-- staging.clj
    |   |   `-- test.clj
    |   `-- logging.properties
    

    我的 project.clj 中有以下内容:

      :resource-paths ["shared" "resources"]
    

    然后我可以在我的 repl 中执行以下操作:

    user> (do (require '[clojure.java.io :as io]) (io/resource "config/boot.clj"))
    #<URL file:/Users/me/this-project/resources/config/boot.clj>
    user> (slurp *1)
    "(use '[caribou.config :only (read-config configure environment)])\n(require '[clojure.java.io :as io])\n..."
    

    如您所见,io/resource 返回一个 URL,然后我可以将其传递给我请求的文件(在配置的资源路径中查找路径片段)。如果将整个应用打包到 uberjar 中进行部署,此代码仍然有效,而在这种情况下,创建 io/file 并调用 getParent 会失败。

    【讨论】:

      【解决方案2】:

      在谷歌搜索了一点之后,我想出了如何做到这一点,并且实际上阅读了 Stackoverflow 上的所有答案。 user83510 实际上在这里回答了这个问题:https://stackoverflow.com/a/11498784/1285782,但答案没有被接受或正确地投票。诀窍如下:

      (-> (ClassLoader/getSystemResource *file*) clojure.java.io/file .getParent)
      

      这为您提供了目录的绝对路径。不漂亮,但有效。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-21
        • 2022-01-10
        • 2022-01-07
        • 1970-01-01
        相关资源
        最近更新 更多