CLOVER🍀

That was when it all began.

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

今回は、Clojureの入出力系の関数の中でも、比較的プリミティブなclojure.java.io名前空間の関数を扱ってみたいと思います。

file

java.io.Fileを作成する関数です。

(use '[clojure.java.io :only (file)])
(println (class (file "clj_java_io.clj")))  ;; => java.io.File

「clj_java_io.clj」というのは、今回作成しているサンプルのスクリプト名です。

引数を複数与えると、左から順番に親ディレクトリとして扱ってくれます。

(println (.exists (file "/usr" "local" "scala" "scala-2.9.2" "bin" "scala"))) ;; => true

これで、ファイル「/usr/loca/scala/scala-2.9.2/bin/scala」を表します。

なお、この関数の裏側にはclojure.java.io/as-file関数が隠れていますが、使い方がほぼ変わらないため割愛。あと、file関数は文字列としてURLも取れるらしいですが、こちらも割愛。

delete-file

ファイルを削除する関数です。以下、使用例。

(use '[clojure.java.io :only (delete-file)])
(spit "hello.txt" "Hello World")
(println (str (slurp "hello.txt") ", " (.exists (file "hello.txt"))))  ;; => Hello World, true
(delete-file "hello.txt")
(println (.exists (file "hello.txt")))  ;; => false

spitで一瞬ファイルを作って、その後すぐに消しています。

なお、この関数はファイルの削除に失敗するとjava.io.IOExceptionを送出します。
こんな感じです。hello2.txtは存在しないファイルです。

(delete-file "hello2.txt")
Exception in thread "main" java.io.IOException: Couldn't delete hello2.txt

この動きを変更するには、delete-file関数の第2引数にtrueを指定します。

(delete-file "hello2.txt" true)

こうすると、削除できなくても例外は送出されません。

make-parents

複数の文字列引数を取り、1番最後の引数をファイル名として、そのファイルの直前までの親ディレクトリが作成されていなかった場合、そのファイルの直前までの親ディレクトリを作成します。

(use '[clojure.java.io :only (make-parents)])
(make-parents "foo" "bar" "hoge.txt")

この例の場合、foo/barディレクトリが作成されます。hoge.txtは、このオペレーションでは作成されません。

以下のように、直接文字列として構築したものを渡してもOKです。

(make-parents "foo/bar/hoge.txt")

このような性格の関数のため、以下のようにファイル名だけを渡しても何も起きません。

(make-parents "hoge.txt")

writer

java.io.BufferedWriterを作成する関数です。オプションとして、キーワードでencodingとappendを取ることができます。

(use '[clojure.java.io :only (writer)])
(with-open [w (writer "java_io.txt" :encoding "UTF-8")]
  (println (class w))  ;; => java.io.BufferedWriter
  (.write w "こんにちは Java")
  (.newLine w)
  (.write w "こんにちは Clojure")
  (.newLine w))

この関数の裏には、clojure.java.io/make-writerが隠れています。

reader

writer関数の対となる、java.io.BufferedReaderを作成する関数です。オプションとして、キーワードでencodingを取ることができます。

(use '[clojure.java.io :only (reader)])
(with-open [rdr (reader "java_io.txt" :encoding "UTF-8")]
  (println (class rdr))  ;; => java.io.BufferedReader
  (loop [line (.readLine rdr)]
    (if (not= line nil)
      (do (println line)
          (recur (.readLine rdr))))))

この関数の裏には、clojure.java.io/make-readerが隠れています。

output-stream

java.io.BufferedOutputStreamを作成する関数です。

(use '[clojure.java.io :only (output-stream)])
(with-open [os (output-stream "java_stream.txt")]
  (println (class os))  ;; => java.io.BufferedOutputStream
  (.write os 1)
  (.write os 2)
  (.write os 3))

この関数の裏には、clojure.java.io/make-output-streamが隠れています。

input-stream

output-streamの対となる、java.io.BufferedInputStreamを作成する関数です。

(use '[clojure.java.io :only (input-stream)])
(with-open [is (input-stream "java_stream.txt")]
  (println (class is))
  (loop [b (.read is)]
    (if (not= b -1)
      (do (println b)
          (recur (.read is))))))

この関数の裏には、clojure.java.io/make-input-streamが隠れています。