在 Clojure 1.3 中,如何读写文件

发布于 2024-12-09 19:45:35 字数 127 浏览 0 评论 0原文

我想知道在 clojure 1.3 中读取和写入文件的“推荐”方式。

  1. 如何读取整个文件
  2. 如何逐行读取文件
  3. 如何写入新文件
  4. 如何向现有文件添加一行

I'd like to know the "recommended" way of reading and writing a file in clojure 1.3 .

  1. How to read the whole file
  2. How to read a file line by line
  3. How to write a new file
  4. How to add a line to an existing file

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

感情废物 2024-12-16 19:45:35

假设我们在这里只处理文本文件,而不是一些疯狂的二进制文件。

第一:如何将整个文件读入内存。

(slurp "/tmp/test.txt")

当文件非常大时不推荐。

第二点:如何逐行读取文件。

(use 'clojure.java.io)
(with-open [rdr (reader "/tmp/test.txt")]
  (doseq [line (line-seq rdr)]
    (println line)))

with-open 宏负责确保读取器在正文末尾关闭。 reader 函数将字符串(也可以执行 URL 等)强制转换为 BufferedReader。 line-seq 提供了一个惰性序列。要求惰性序列的下一个元素会导致从读取器读取一行。

请注意,从 Clojure 1.7 开始,您还可以使用转换器来读取文本文件。

第三点:如何写入新文件。

(use 'clojure.java.io)
(with-open [wrtr (writer "/tmp/test.txt")]
  (.write wrtr "Line to be written"))

同样,with-open 会注意 BufferedWriter 在正文末尾关闭。 Writer 将字符串强制转换为 BufferedWriter,您可以通过 java 互操作使用该字符串:(.write wrtr "something")。

您还可以使用 spit >,与 slurp 相反:

(spit "/tmp/test.txt" "Line to be written")

数字 4:向现有文件追加一行。

(use 'clojure.java.io)
(with-open [wrtr (writer "/tmp/test.txt" :append true)]
  (.write wrtr "Line to be appended"))

与上面相同,但现在带有追加选项。

或者再次使用 spit,与 slurp 相反:

(spit "/tmp/test.txt" "Line to be written" :append true)

PS: 为了更明确地说明您正在读取和写入文件的事实,不是别的,您可以首先创建一个 File 对象,然后将其强制转换为 BufferedReader 或 Writer:

(reader (file "/tmp/test.txt"))
;; or
(writer (file "tmp/test.txt"))

文件函数也在 clojure.java.io 中。

PS2:有时能够很方便地查看当前目录(即“.”)是什么。您可以通过两种方式获取绝对路径:

(System/getProperty "user.dir") 

或者

(-> (java.io.File. ".") .getAbsolutePath)

Assuming we're only doing text files here and not some crazy binary stuff.

Number 1: how to read an entire file into memory.

(slurp "/tmp/test.txt")

Not recommended when it is a really big file.

Number 2: how to read a file line by line.

(use 'clojure.java.io)
(with-open [rdr (reader "/tmp/test.txt")]
  (doseq [line (line-seq rdr)]
    (println line)))

The with-open macro takes care that the reader is closed at the end of the body. The reader function coerces a string (it can also do a URL, etc) into a BufferedReader. line-seq delivers a lazy seq. Demanding the next element of the lazy seq results into a line being read from the reader.

Note that from Clojure 1.7 onwards, you can also use transducers for reading text files.

Number 3: how to write to a new file.

(use 'clojure.java.io)
(with-open [wrtr (writer "/tmp/test.txt")]
  (.write wrtr "Line to be written"))

Again, with-open takes care that the BufferedWriter is closed at the end of the body. Writer coerces a string into a BufferedWriter, that you use use via java interop: (.write wrtr "something").

You could also use spit, the opposite of slurp:

(spit "/tmp/test.txt" "Line to be written")

Number 4: append a line to an existing file.

(use 'clojure.java.io)
(with-open [wrtr (writer "/tmp/test.txt" :append true)]
  (.write wrtr "Line to be appended"))

Same as above, but now with append option.

Or again with spit, the opposite of slurp:

(spit "/tmp/test.txt" "Line to be written" :append true)

PS: To be more explicit about the fact that you are reading and writing to a File and not something else, you could first create a File object and then coerce it into a BufferedReader or Writer:

(reader (file "/tmp/test.txt"))
;; or
(writer (file "tmp/test.txt"))

The file function is also in clojure.java.io.

PS2: Sometimes it's handy to be able to see what the current directory (so ".") is. You can get the absolute path in two ways:

(System/getProperty "user.dir") 

or

(-> (java.io.File. ".") .getAbsolutePath)
和影子一齐双人舞 2024-12-16 19:45:35

如果文件适合内存,您可以使用 slurp 和 spit 读取和写入它:

(def s (slurp "filename.txt"))

(s 现在包含文件内容作为字符串)

(spit "newfile.txt" s)

如果它不退出并写入文件内容,则会创建 newfile.txt。
如果你想追加到文件中,你可以

(spit "filename.txt" s :append true)

按行读取或写入文件,你可以使用Java的读取器和写入器。它们被包装在命名空间 clojure.java.io 中:

(ns file.test
  (:require [clojure.java.io :as io]))

(let [wrtr (io/writer "test.txt")]
  (.write wrtr "hello, world!\n")
  (.close wrtr))

(let [wrtr (io/writer "test.txt" :append true)]
  (.write wrtr "hello again!")
  (.close wrtr))

(let [rdr (io/reader "test.txt")]
  (println (.readLine rdr))
  (println (.readLine rdr)))
; "hello, world!"
; "hello again!"

请注意,slurp/spit 和 reader/writer 示例之间的区别在于,后者中的文件保持打开状态(在 let 语句中),并且读取和写入被缓冲,因此重复读取/写入文件时效率更高。

以下是更多信息: slurp
clojure.java.io
Java 的 BufferedReader
Java 的 Writer

If the file fits into memory you can read and write it with slurp and spit:

(def s (slurp "filename.txt"))

(s now contains the content of a file as a string)

(spit "newfile.txt" s)

This creates newfile.txt if it doesnt exit and writes the file content.
If you want to append to the file you can do

(spit "filename.txt" s :append true)

To read or write a file linewise you would use Java's reader and writer. They are wrapped in the namespace clojure.java.io:

(ns file.test
  (:require [clojure.java.io :as io]))

(let [wrtr (io/writer "test.txt")]
  (.write wrtr "hello, world!\n")
  (.close wrtr))

(let [wrtr (io/writer "test.txt" :append true)]
  (.write wrtr "hello again!")
  (.close wrtr))

(let [rdr (io/reader "test.txt")]
  (println (.readLine rdr))
  (println (.readLine rdr)))
; "hello, world!"
; "hello again!"

Note that the difference between slurp/spit and the reader/writer examples is that the file remains open (in the let statements) in the latter and the reading and writing is buffered, thus more efficient when repeatedly reading from / writing to a file.

Here is more information: slurp spit
clojure.java.io
Java's BufferedReader
Java's Writer

悲歌长辞 2024-12-16 19:45:35

关于问题 2,有时希望将行流作为第一类对象返回。为了将其作为惰性序列,并且仍然在 EOF 时自动关闭文件,我使用了以下函数:

(use 'clojure.java.io)

(defn read-lines [filename]
  (let [rdr (reader filename)]
    (defn read-next-line []
      (if-let [line (.readLine rdr)]
       (cons line (lazy-seq (read-next-line)))
       (.close rdr)))
    (lazy-seq (read-next-line)))
)

(defn echo-file []
  (doseq [line (read-lines "myfile.txt")]
    (println line)))

Regarding question 2, one sometimes wants the stream of lines returned as a first-class object. To get this as a lazy sequence, and still have the file closed automatically on EOF, I used this function:

(use 'clojure.java.io)

(defn read-lines [filename]
  (let [rdr (reader filename)]
    (defn read-next-line []
      (if-let [line (.readLine rdr)]
       (cons line (lazy-seq (read-next-line)))
       (.close rdr)))
    (lazy-seq (read-next-line)))
)

(defn echo-file []
  (doseq [line (read-lines "myfile.txt")]
    (println line)))
椵侞 2024-12-16 19:45:35

要逐行读取文件,您不再需要诉诸互操作:

(->> "data.csv"
      io/resource
      io/reader
      line-seq
      (drop 1))

这假设您的数据文件保存在资源目录中,并且第一行是可以丢弃的标头信息。

To read a file line by line you no longer need to resort to interop:

(->> "data.csv"
      io/resource
      io/reader
      line-seq
      (drop 1))

This assumes that your data file is kept in the resources directory and that the first line is header information that can be discarded.

白日梦 2024-12-16 19:45:35

这是读取整个文件的方法。

如果该文件位于资源目​​录中,则可以执行以下操作:

(let [file-content-str (slurp (clojure.java.io/resource "public/myfile.txt")])

记住 require/use clojure.java.io

This is how to read the whole file.

If the file is in the resource directory, you can do this:

(let [file-content-str (slurp (clojure.java.io/resource "public/myfile.txt")])

remember to require/use clojure.java.io.

与往事干杯 2024-12-16 19:45:35
(require '[clojure.java.io :as io])
(io/copy (io/file "/etc/passwd") \*out*\)
(require '[clojure.java.io :as io])
(io/copy (io/file "/etc/passwd") \*out*\)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文