Scala+CommonsIOでFileを強化してみた
-
概要
Scalaのファイル操作はあまり気合が入っていないので、個人的にはCommonsIOなんかを使ってファイル処理をすることが多かったりする。でも、Commons使うと文字数が増えてコードがもっさりしてしまう。
待っていればscalax.ioが普及するなりなんなりで便利にはなっていくと思うけど、まだイマイチ方向性に確証が持ててないので、当面のしのぎとして、少ない労力でファイル操作周りをなんとかしようと思った。
というわけで書いたのが、暗黙の型変換を利用してjava.io.FileからCommonsの機能を使えるようなクラス。
仕事先とかでも使いたくなりそうな気がするので、Mavenレポジトリを置いておく。ざっくり書いただけなのでまだ使い物になるかどうかは不明。
@Author mwSoft
@Date 2011/06/30
@Env Scala2.9.0.1 -
できることの一例
jp.mwsoft.commonsfile.CommonsFileというクラスをimportすると使える。
// importすると、java.io.FileがCommonsFileに暗黙の型変換される // type File = java.io.Fileも定義している import jp.mwsoft.commonsfile.CommonsFile._ // ファイルを文字列として読み込む new File("foo.txt").readToString("utf-8") // 文字列をファイル出力 new File("foo.txt").write("出力する文字", "utf-8") // touchコマンドと同様の動き new File("foo.txt").touch // 拡張子の取得 new File("foo.txt").extension // URL指定でリソースをファイルへコピー new File("foo.txt").copyFromURL("http://www.yahoo.co.jp/")
こんな感じで、CommonsIOのFileUtilsとかFilenameUtilsとかに付いている機能をjava.io.Fileから呼び出せるようにした。
中身はCommonsの機能を叩いているだけなので、独自実装はほとんどしてない。
FileUtils
http://commons.apache.org/io/apidocs/org/apache/commons/io/FileUtils.htmlFilenameUtils
http://commons.apache.org/io/apidocs/org/apache/commons/io/FilenameUtils.html -
ダウンロード
Jarとかソースとか
https://github.com/mwsoft/maven/tree/master/jp/mwsoft/commonsfile/0.0.1Commons IOが必要
http://commons.apache.org/io/download_io.cgiScalaDoc
commonsfile-scaladocs/#jp.mwsoft.commonsfile.CommonsFile<!-- Mavenでの利用 --> <!-- リポジトリはgithubに置いた --> <repository> <id>git.mwsoft</id> <url>https://github.com/mwsoft/maven/raw/master/</url> </repository> <!-- dependencyはこんな感じ --> <dependency> <groupId>jp.mwsoft</groupId> <artifactId>commonsfile</artifactId> <version>0.0.1</version> </dependency>
-
やったこと
・FileUtilsとFilenameUtilsの中から使えそうな機能を片っ端から入れた
・長い関数名はたまに省略してる(Directory → Dir、 getPath → path)
・write関連の関数はthisを返す
・copyやmove関連の関数は出力後のファイルを返す
・eachLineとnotExistsとappendだけはどうしても欲しかったので勝手に入れた -
ファイルパスの取得
// パスの取得 new File("foo.txt").path //=> foo.txt // cannonicalPathの取得 new File("foo.txt").canonicalPath //=> /hoge/foo.txt // 親パスの取得(java.io.Fileのparent : 相対パスなので上がないとnullになる) new File("foo.txt").parentPath //=> null // 絶対パスから親パス取得 new File("foo.txt").canonicalFile.parentPath //=> /hoge // ファイル名の取得 new File("foo.txt").name //=> foo.txt // 拡張子を除いたファイル名の取得 new File("foo.txt").baseName //=> foo
FilenameUtils系のものは、getPath()で取れた値に対して処理をしている。ので、絶対パスの結果が帰ってくるわけではない。
絶対パスで処理したい場合は、「val file = new File("foo").canonicalFile」でファイルを取る。
「new File("/foo/")」に対してgetPath()をすると最後のスラッシュが取れて「/foo」が返るあたりがクセモノ。
-
ファイルの読み/書き/削除
// ファイルを文字列として読み込む new File("foo.txt").readToString("utf-8") // ファイルをArray[Byte]で読み込む new File("foo.txt").readToByteArray() // 1行ずつ読み込む(LineIteratorを使用) new File("foo.txt") eachLine (str => println(str)) // 文字列をファイル出力(Array[Byte]でも出力可) new File("foo.txt").write("test", "utf-8") // 文字列をファイルに追記 new File("foo.txt").append("bar", "utf-8") // touchコマンドと同様の動き new File("foo.txt").touch // ファイルの強制削除(Directoryも削除する) new File("foo.txt").forceDelete() // ファイルを例外を発生させずに削除(Directoryも削除する。結果はBooleanで返す) new File("foo.txt").deleteQuietly() // ディレクトリの中身を空にする new File("hoge/").cleanDir()
moveFileは違うファイルシステムに移動をする場合は、コピーして削除する動作になるのでFile#renameToより汎用性がある。
-
ファイルのコピー/移動
// URL指定でリソースをファイルへコピー new File("foo.txt").copyFromURL("http://www.yahoo.co.jp/") // ファイルのコピー new File("foo.txt").copyFile("bar.txt") // ファイルを移動 new File("foo.txt").moveFile("baz.txt") // コピーや移動は出力ファイルを返すので、繋ぐことも可能 new File("foo.txt") copyFile ("bar.txt") moveFile ("baz.txt")
-
その他
// FileInputStreamを開く new File("foo.txt").openInputStream() // FileOutputStreamを開く new File("foo.txt").openOutputStream() // ディレクトリの作成(サブディレクトリもまとめて作る) new File("bar/baz").forceMkdir() // 新しい or 古い比較 new File("foo.txt") isNewer new File("bar.txt") new File("foo.txt") isOlder new File("bar.txt") // シンボリックリンク判定 new File("foo.txt").isSymlink // 再帰的にディレクトリ配下のファイルを取得する new File("bar").listFilesRecursive // 指定した拡張子のファイルだけ取得する new File(".").listFiles(Array("txt"))
-
まとめ
CommonsIOはファイルシステムまたいだ時はどうとか、NFSの場合の遅延はどうするとか、シンボリックリンクの場合はどうするとか、自分的によく引っかかるところをケアしてくれてるので助かっている。
その辺が気楽に扱えるものがScalaで出るかというと怪しいので(Java系のポリシー的な意味でも怪しい部分がある)、当面はこんな感じで生きていこうかと思う。
とりあえずしばらく使ってみて、使い物になるようにしたい。