web-dev-qa-db-ja.com

Clojure 1.3では、ファイルを読み書きする方法

Clojure 1.3でファイルを読み書きする「推奨」方法を知りたいのですが。

  1. ファイル全体を読む方法
  2. ファイルを1行ずつ読み取る方法
  3. 新しいファイルを書く方法
  4. 既存のファイルに行を追加する方法
159
jolly-san

ここではテキストファイルのみを実行し、クレイジーなバイナリファイルは実行しないものとします。

番号1:ファイル全体をメモリに読み込む方法

(Slurp "/tmp/test.txt")

本当に大きなファイルの場合はお勧めしません。

数2:ファイルを1行ずつ読み込む方法

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

with-openマクロは、リーダーが本文の最後で閉じられるようにします。リーダー関数は、文字列(URLなども可能)をBufferedReaderに強制します。 line-seqは遅延シーケンスを提供します。レイジーseqの次の要素を要求すると、リーダーから読み取られる行になります。

Clojure 1.7以降では、テキストファイルの読み取りに transducers を使用することもできます。

数3:新しいファイルへの書き込み方法

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

繰り返しますが、with-openは、BufferedWriterが本文の最後で閉じられるように注意します。ライターは、Java interopを介して使用するBufferedWriterに文字列を強制します:(.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:現在のディレクトリ( "。")が何であるかを確認できると便利な場合があります。次の2つの方法で絶対パスを取得できます。

(System/getProperty "user.dir") 

または

(-> (Java.io.File. ".") .getAbsolutePath)
264
Michiel Borkent

ファイルがメモリに収まる場合は、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とリーダー/ライターの例の違いは、後者ではファイルが(letステートメントで)開いたままであり、読み取りと書き込みがバッファリングされるため、ファイルへの読み取り/書き込みを繰り返し行う場合により効率的であることに注意してください。

詳細は次のとおりです。 Slurpspitclojure.Java.ioJava's BufferedReaderJava's Writer =

32
Paul

質問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)))
6
satyagraha

これは、ファイル全体を読み取る方法です。

ファイルがリソースディレクトリにある場合、これを行うことができます。

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

clojure.Java.ioを要求/使用することを忘れないでください。

1
joshua
(require '[clojure.Java.io :as io])
(io/copy (io/file "/etc/passwd") \*out*\)
0
Dima Fomin

ファイルを1行ずつ読み取るために、相互運用に頼る必要はなくなりました。

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

これは、データファイルがリソースディレクトリに保持され、最初の行が破棄可能なヘッダー情報であることを前提としています。

0
Chris Murphy