カテゴリー
コンピューター

Gradle で Java からエクセルなどのファイルを扱う方法

まとめ

  • build.gradle で java プラグインを読み込む。
  • エクセルなどのファイルは src/main/resouces に置く。
  • Java ファイルでは、getClassLoader().getResourceAsStream(“aaaa/sample.xls”) などと書けばエクセルにアクセスできる。
  • getResourceAsStream メソッドの引数には、src/main/resources からの相対パスを記述する。

はじめに

Fisshplate でテンプレートに埋め込まれるのはゲッターメソッド – oki2a24 にて試行錯誤して学んだことを残します。

ソースコードは、README に使い方を追記する · oki2a24/testfisshplate@9b9ffb7 時点のコミットで全体像がつかめるかと思います。

Java からエクセルなどのファイルに簡単にアクセスするための、getClass().getResourceAsStream() の使い方がよくわからない

Fisshplate – Fisshplate Home のサンプルコードには次の行でエクセルファイルにアクセスしています。

InputStream is = getClass().getResourceAsStream("/FPTemplateTest.xls");

ところが、このまま書いてもコンパイルエラーとなりますした><。getClass() を実行するオブジェクトが指定されていないからでしょう。

InputStream is = this.getClass().getResourceAsStream("sample.xls");

でもダメ。this が書いてあるのは、public static void main メソッドで、static なメソッドからは this にアクセスできません。次のエラーメッセージが出ました。

[Java] Cannot make a static reference to the non-static method getClass() from the type Object

InputStream is = App.class.getResourceAsStream("sample.xls");

これでようやくうまくいきました。

あとからふと思いついて、試したところ、

InputStream is = new App().getClass().getResourceAsStream("sample.xls");

でもうまくいきました。getClass() はオブジェクトのメソッドなのですから、インスタンス化すればいいだけの話ですよね、そりゃそうだ、という話です。

参考ページ

エクセルファイルを Java からいい感じに参照したい

コンパイルエラーは解消できましたが、実行するとエラーとなりました。

$ gradle run

> Task :run
Hello world.

BUILD SUCCESSFUL in 2s
2 actionable tasks: 2 executed
oki2a24:testfisshplate$ gradle run

> Task :run FAILED
Hello world.
Exception in thread "main" java.lang.NullPointerException
        at org.apache.poi.poifs.filesystem.POIFSFileSystem.closeInputStream(POIFSFileSystem.java:188)
        at org.apache.poi.poifs.filesystem.POIFSFileSystem.<init>(POIFSFileSystem.java:158)
        at org.seasar.fisshplate.template.FPTemplate.process(FPTemplate.java:90)
        at App.main(App.java:27)

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':run'.
> Process 'command '/Users/oki2a24/.sdkman/candidates/java/10.0.0-openjdk/bin/java'' finished with non-zero exit value 1

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 1s
2 actionable tasks: 1 executed, 1 up-to-date
$

どうやらエクセルファイルにアクセスできないようです。sample.xls は App.java と同じディレクトリに置きました。

そこで、Gradle によってビルド生成物が置かれる場所、build/classes/java/main (ここには App.class もあります) にコピーしました。 これでうまくいきました。

ただ、毎回コピーするのは面倒です。

調べてみて、次のページのリソースについての説明が参考になりました。

いままで、resources ディレクトリにはピンと来ていませんでした。なんか resources ディレクトリがあって、中に Java ファイル以外が入っているな、その程度です。その認識の先に行くことができました♪

今回の件でつぎのように学びました。エクセルファイルを resources ディレクトリに入れておくことで、ビルドされた Java クラスファイルからアクセスできるようになる

もうちょっと調べてみました。

なぜって、App.class と同じディレクトリに sample.xls を置いた場合、同じディレクトリにいるので getResourceAsStream(“sample.xls”) でアクセスできるのは納得できます。
実際に、resources ディレクトリを削除して、App.class と同じディレクトリに sample.xls を置き、System.out.println(App.class.getResource("sample.xls")); を書いてどのファイルにアクセスしているかを確認してみました。

結果は、file:/Users/oki2a24/testfisshplate/build/classes/java/main/sample.xls となりました。そりゃそうですね。

次に、resources ディレクトリを作成し、ここに sample.xls を移動し、gradle clean run してみます。

結果は、file:/Users/oki2a24/testfisshplate/build/resources/main/sample.xls です。勝手に resources/main/sample.xls を見に行っています。びっくりです。もちろんエクセルファイルへのアクセス方法は変更していません。InputStream is = App.class.getResourceAsStream("sample.xls"); のままです。おそるべし Gradle Java プラグイン!

src/main/resources にさらにディレクトリを作った場合の Java からのアクセス方法

次に、src/main/java ディレクトリと src/main/resources ディレクトリの対応について調べてみました。

試しに、src/main/resources/aaaa/sample.xls へと移動してみたところ、エクセルファイルへはアクセスできなくなりました。

ディレクトリを合わせればよいのかなと思い、src/main/java/App.java を src/main/java/aaaa/App.java へと移動してみましたが、これもダメ。
それではと思って、App.class.getClassLoader().getResourceAsStream("aaaa/sample.xls") などとエクセルファイルへはディレクトリも含めて指定してみまして、これでうまくいきました。

単純に、resources ルートからのパスを書けば、ファイルへアクセスできる のですね、楽ちんです♪

おわりに

Gradle、そしておそらく Maven プロジェクトの使い方をさらに詳しく知ることができたと思います。

嬉しく思います。

以上です。

コメントを残す