今回は、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))
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))))))
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))
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))))))