CLOVER🍀

That was when it all began.

Clojureで入出力を扱う(clojure.core)

Clojureのcoreライブラリの中でも、日常で比較的使いそうなIO系の関数をちょっと調べてみました。

read-line

標準入力から1行読み込みます。以下、サンプル。

(print "type keyword => ")
(flush)
(def line (read-line))
(print (str "Your typed => " line))
(newline)

flushは標準出力をフラッシュする関数、newlineは標準出力に改行を出力する関数です。これを実行すると、以下のような実行結果となります。

type keyword => こんにちは、世界
Your typed => こんにちは、世界

type keyword =>の後に続いている「こんにちは、世界」は、もちろん自分で入力したものです。
なお、変数lineにこの時入力された文字列を束縛しています。

spit

ファイルパスと文字列を与えると、その内容をファイルに書き出す関数です。
slurp関数の対らしいです。以下の例では、先の例で標準入力から読み出した文字列を、改行付きでファイルoutput.txtに出力します。

(spit "output.txt" (str line "\n"))

オプションとして、clojure.java.io/writerと同じものが渡せるんだそうな。つまり、以下のような指定が可能らしいです。

(spit "output.txt" (str line "\n") :append true :encoding "UTF-8")

キーワードappendでファイルに追記するかどうかを、encodingキーワードで出力時の文字エンコーディングを指定します。

slurp

与えられたファイルパスから、ファイルの内容を文字列として読み出す関数です。以下の例では、ファイルoutput.txtからファイルの内容を読み出し、標準出力に書き出します。

(print (slurp "output.txt"))

こちらも、オプションとしてclojure.java.io/readerと同じものが渡せるそうです。

(print (slurp "output.txt" :encoding "UTF-8"))

なお、slurpにはURLなども引数として渡せます。例えば、以下のコードでGoogleのサイトのHTMLがコンソールに出力されます。

(print (slurp "http://google.co.jp"))

spitもそうですが、何が引数として取れるのかはclojure.java.io内に定義されている関数を読んだ方がよいみたいですね。

with-open

ReaderやWriterを引数として渡し、処理の終了時には自動的にcloseを呼び出すマクロです。以下、使用例です。

(import '(java.io BufferedReader InputStreamReader FileInputStream))
(with-open [r (BufferedReader. (InputStreamReader. (FileInputStream. "output.txt")))]
  (loop [l (.readLine r)]
    (if (not= nil l)
      (do (println l)
          (recur (.readLine r))))))

ファイルを開いて、コンテンツがある限りBufferedReader#readLineを呼び出し、コンソールに出力します。doがないと、1回出力するだけで終了してしまうので注意です。

一応、今回作成したコードの全体です。
clj_io.clj

(print "type keyword => ")
(flush)
(def line (read-line))
(print (str "Your typed => " line))
(newline)

;;(spit "output.txt" (str line "\n") :append true :encoding "UTF-8")
(spit "output.txt" (str line "\n"))

;;(print (slurp "output.txt" :encoding "UTF-8"))
(print (slurp "output.txt"))

(import '(java.io BufferedReader InputStreamReader FileInputStream))
(with-open [r (BufferedReader. (InputStreamReader. (FileInputStream. "output.txt")))]
  (loop [l (.readLine r)]
    (if (not= nil l)
      (do (println l)
          (recur (.readLine r))))))

実行例。

$ clj clj_io.clj 
type keyword => こんにちは、世界
Your typed => こんにちは、世界
こんにちは、世界
こんにちは、世界
$ cat output.txt 
こんにちは、世界

今後は、clojure.java.ioを見ていこうと思います。それにしても、APIドキュメントはClojure自身のサイトよりも、以下の方が見やすく整理されていてよいですね。
http://clojuredocs.org/