読者です 読者をやめる 読者になる 読者になる

プログラムdeタマゴ

nodamushiの著作物は、文章、画像、プログラムにかかわらず全てUnlicenseです

Eclipseプラグイン開発: リソースパス関連

Eclipse プラグイン開発 目次


 Javaでファイル、ディレクトリを操作する場合、java.io.Fileやjava.nio.Pathを用いて表現します。

 EclipseではIPathないし、IResourceを用いて表現するのですが、これもうほんと、使いにくい。
 といっても、Eclipseでファイルを扱おうと思ったら避けることは出来ませんので、理解して付き合っていくしかありません。

IPath

 IPathはJavaのAPIで言えば、java.nio.Pathとほぼ同等の機能です。ファイルやディレクトリなどの場所(パス)を表現します。

 Eclipseプラグイン開発において、IPathは主に以下のパスを表現します。

  • フルパス:ワークスペースをルートとする、ワークスペース空間における絶対パス表現
  • ロケーション(ローカルシステム)パス:OS固有の絶対パス表現
  • 相対パス:絶対パスではないパス表現


f:id:nodamushi:20170403014824p:plain:right

 フルパスというのは、ワークスペースをルートとする、Eclipseシステム系の絶対パスを示します。
 たとえば、右図の様なワークスペースのプロジェクト構造をしているとき、AプロジェクトのA.javaは「/A/src/A.java」と表現され、BプロジェクトのdlinkフォルダのTest.classは「/B/dlink/Test.class」と表現されます。
 ルートであるワークスペースのパスは「/」です。この辺はUnixと同じ表現ですね。@でも何でも良いから別な文字にしときゃ良かったのに。

 

 一方で、ロケーションパスというのはOSのファイルシステムにおける絶対パスを表します。
 実際にフルパス、ロケーションパスを見たければ、プログラムを書かなくても、プロパティビューから確認することが出来ます。
 右図のワークスペースは、「F:\workspace」に配置しているのですが、プロジェクトAとプロジェクトBのローカルパスを表示すると下図の様に「F:\workspace」とは全然関係ないところに配置されていることが分かります。
 従って「ワークスペースのディレクトリ(F:\workspace)」+「フルパス」としてもOS上のファイルパスを取得することが出来るとは限りません。
f:id:nodamushi:20170403015926p:plain


 なお、ロケーションパスには、生ロケーションパス(Raw Location Path)パスが存在しますが、これは使うことないと思います。Eclipseのフォルダリンクは、リンク先を絶対パスで指定するタイプのものと、変数で指定する仮想リンクがあるのですが、生ロケーションパスが表現するのは後者のほうです。例えば、Test.javaはこんな風に出てきます。「PARENT-1-PROJECT_LOC/java/Test.java」。普通にロケーションパスを取得すれば、変数の所は解決してくれるので、考える必要はありません。

 相対パスは、Bundle内のリソースパスだったり、特定のパスからの相対パスだったり等、使う場所や条件によって意味が変わる通常の相対パスです。

IResource

 IResourceはワークスペース空間におけるリソース(ワークスペース、プロジェクト、フォルダ、ファイル)を表現するインターフェースです。ワークスペース空間におけるリソースというのは、要するにフルパスで表現できるリソースを表します。
 JavaのAPIでいうと、パス以外の付加情報や操作機能を持っているという点でjava.io.Fileがよく似ています。

 java.io.Fileと違うのは、ルート(ワークスペース)、プロジェクト、フォルダ、ファイルと4種類のインターフェースに派生する点と、IFile(ファイルを表現するIResource)から内容を編集したときに、Eclipseのローカル履歴に変更情報を残すことが出来る点でしょう。

IResource 説明 取得方法
IWorkspaceRoot ワークスペースを表す IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IProject プロジェクトを表す IProject project = root.getProject("B");
IFolder フォルダーを表す container.getFolder(new Path("hoge"));
IFile ファイルを表す container.getFile(new Path("hoge.txt"));


 containerはIWorkspaceRootか、IProject、IFolderのことです。(IContainerのインターフェース)渡すIPathは、containerからの相対パスです。

 getProject,getFolder,getFileによるプロジェクト、フォルダー、ファイルの取得は、存在しないリソースも表します。この辺はもうAPI設計のミスだと思うわー。newProject,createFolderとかにして、存在する場合はエラーにすべきだと思うわー。

 IProject、IFolder、IFileに関わらず、存在する場合のみIResourceを取得したい場合は、container.findMemberメソッドを使います。
 

IPathからjava.io.Fileやjava.nio.Pathへの変換

 Eclipse内部だけで完結するならIPath,IResourceで全て処理すれば良いのだが、大概そうもいかない。普通のライブラリって、ファイル表現にFileだったりPathを使うわけで、IPathやIResourceのままだと困るのだ。

 結論を言うと、IPathやIResourceから確実にFileやPathに変換する方法はない。
 基本は「IPath→IResource→FileやPath」という変換手順を辿らなければならないが、「IPath→IResource」の段階で絶対の手順というものはないし、「IResource→FileやPath」も必ず成功するとは限らない。

IPath→IResource

 まずは渡されたIPathがフルパスなのか、ロケーションパスなのか、相対パスなのか考えなくてはならない。相対パスの場合は、何に対して相対なのかで話が変わるから、ここでは考えない。
 
 フルパスなのか、ロケーションパスなのかについては、Windowsの場合は楽です。「~:\」ないし「\\」から始まっていたらロケーションパスです。そのままFileやPathに変換しましょう。しかし、これがUnix系の場合だったら…どうすんだろうね。


 で、フルパスからIResourceに変換する一番簡単な方法は以下の方法だと思う。

IResource resource = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path("パス"));

 なお、パスが示す先がFolderであっても、ファイルとしてアクセスするような処理をしない限り、実はgetFileで特に問題ない。

 findMemberだと、存在しないファイルのパスを解決できないので、getFileを使うと良い。

IResource→File,Path

 単純には以下のようにすれば良い。しかし、プロジェクトを閉じている場合や、リンクを解決できない場合などで、getLocationはnullが返ることがあるので、要注意

File file = resource.getLocation().toFile();
Path path = Paths.get(resource.getLocation().toOSString());