Top / Eclipse / プラグイン開発のTIPS集 / ワークスペースのリソースを取り扱う

プラグインからEclipseのワークスペース上のリソースを操作する方法をまとめます。

全体の構成

Eclipseのワークスペース関連のAPIは

  • ワークスペース全体を表すorg.eclipse.core.resources.IWorkspaceRoot?
  • その下の各プロジェクトorg.eclipse.core.resources.IProject
  • プロジェクト内のリソースorg.eclipse.core.resources.IResource

のような構成となっています。これらへの参照を取得して、そのオブジェクトのメソッドを呼び出してワークスペースを操作するわけですね。

あ、これらのAPIを使用するには

org.eclipse.core.resources

を依存関係に追加してください。

ワークスペースの参照を取得する

IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceRoot root = workspace.getRoot();

これでワークスペースへの参照を取得することができます。このIWorkspaceRoot? から各プロジェクトへの参照を取得することができます。

プロジェクトへの参照を取得する

IWorkspaceRoot root = workspace.getRoot();
IProject[] projects = root.getProjects();

これで現在起動しているワークスペース内のプロジェクトを配列で取得することできました。また、

IProject project = root.getProject([プロジェクト名の文字列]);

などとしてプロジェクト名指定で参照を取得することもできます。

プロジェクトを作成する

先のメソッドでプロジェクトを取得することができましたが、プロジェクトを作成するには以下のようにします。

IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IProject project = root.getProject("hogehoge");
if (!project.exists()) {
  try {
    project.create(null);
  } catch (CoreException e1) {
    // TODO 自動生成された catch ブロック
    e1.printStackTrace();
  }
}

プロジェクトが存在するときにcreateを実行すると

org.eclipse.core.internal.resources.ResourceException: リソース /hogehoge はすでに存在します。

のように例外が発生するため、存在チェックをしています。またプロジェクトを作成する

IProject#create(IProgressMonitor monitor)

メソッドは時間がかかる場合があるため、引数にIProgressMonitor?を取ります。ここではとりあえずnullを渡してますが。

プロジェクト内の各リソース

プロジェクト内のリソースはすべて

org.eclipse.core.resources.IResource

というインタフェース(とそのサブインタフェース)を実装しています。以下のような構成ですね。

IResource.png

プロジェクト内のリソースは

↓projectはIProjectのインスタンス
project.accept(new IResourceVisitor() {
  public boolean visit(IResource resource) throws CoreException {
    switch (resource.getType()) {
    case IResource.FILE:
      logger.debug("飛んできたVisitor: " + resource + " ファイルだ");
      // IJavaElement file = JavaCore.create(resource);
      // if (file instanceof ICompilationUnit) {
      // logger.debug("さらにICompilationUnitだ");
      // } else {
      // logger.debug("でもICompilationUnitじゃない");
      // }
      break;
    case IResource.FOLDER:
      logger.debug("飛んできたVisitor: " + resource + " フォルダだ");
      break;
    case IResource.PROJECT:
      logger.debug("飛んできたVisitor: " + resource + " プロジェクトだ");
      break;
    case IResource.ROOT:
      logger.debug("飛んできたVisitor: " + resource + " ROOTだ");
      break;
    default:
      logger.debug("飛んできたVisitor: " + resource + " その他だ");
      break;
    }
    return true;
  }
});

などとすることで取得できます。これはVisitorパタンになっていて、プロジェクト内のツリーを走査していきます。走査したときにvisitメソッドが呼ばれるので、引数のresourceから情報を取り出せばよいわけですね。またこのIResource#getType()を使って型のタイプを取得することができます。タイプは

 public static final int FILE = 0x1;
 public static final int FOLDER = 0x2;
 public static final int PROJECT = 0x4;
 public static final int ROOT = 0x8;

などがあるみたいですね。ROOTってのはようわからんのですが。

上のコードではたとえば以下のような結果が得られます。

飛んできたVisitor: P/Samples プロジェクトだ
飛んできたVisitor: F/Samples/source フォルダだ
飛んできたVisitor: F/Samples/source/nu フォルダだ
飛んできたVisitor: F/Samples/source/nu/mine フォルダだ
飛んできたVisitor: F/Samples/source/nu/mine/kino フォルダだ
飛んできたVisitor: L/Samples/source/nu/mine/kino/BL.java ファイルだ
飛んできたVisitor: F/Samples/classes フォルダだ
飛んできたVisitor: F/Samples/classes/nu フォルダだ
飛んできたVisitor: F/Samples/classes/nu/mine フォルダだ
飛んできたVisitor: F/Samples/classes/nu/mine/kino フォルダだ
飛んできたVisitor: L/Samples/classes/nu/mine/kino/BL.class ファイルだ
飛んできたVisitor: L/Samples/build.properties ファイルだ
飛んできたVisitor: F/Samples/META-INF フォルダだ
飛んできたVisitor: L/Samples/META-INF/MANIFEST.MF ファイルだ
飛んできたVisitor: L/Samples/.project ファイルだ
飛んできたVisitor: L/Samples/.classpath ファイルだ

Visitor以外の方法

IResourceのサブインタフェースIContainerに定義されている

public IResource[] members() throws CoreException;

を使用して、

IResource[] resources = project.members();
for (IResource resource : resources) {
  System.out.println(resource);
}

などとして子要素を取得することもできます。結果は

L/Samples/.classpath
L/Samples/.project
F/Samples/META-INF
L/Samples/build.properties
F/Samples/classes
F/Samples/source

です。でもこれだと一階層下のリソースしか取得できないですね。ディレクトリツリーを末端まで走査するには、自前で再帰的に処理する必要がありそうですね。

ディレクトリを作成する

プロジェクト内にディレクトリやファイルを作成する方法です。ディレクトリの作成は

  • プロジェクトを取得
  • プロジェクトのルートから相対的なパスを取得
  • 実際に生成する

といった手順となります。たとえばプロジェクトHogeProject?に対して

/HogeProject/tmp/xml

というディレクトリを掘るコードは以下のようなります。

IFolder tmpDir = project.getFolder(new Path("tmp")); <-相対的なパスを取得
if (!tmpDir.exists()) {
    tmpDir.create(false, true, null);  <-実際に作成
}
IFolder xmlDir = tmpDir.getFolder(new Path("xml"));
if (!xmlDir.exists()) {
    xmlDir.create(true, true, null);
}
IFolder tmpDir = project.getFolder(new Path("tmp"));

で、プロジェクト直下にディレクトリtmpを作成します。作成といってもワークスペースだけであって実際にファイルシステム上に作成はされていません。実際にディレクトリを掘るのが

tmpDir.create(false, true, null);

です。またサンプルコードは、ファイルが存在しない場合作成するという処理になってますね。ちなみにこの存在チェックは、ワークスペース上に存在するかであって、実際ファイルシステム上にあるかどうかのチェックはしていません。

このIFolderのメソッド

public void create(boolean force, boolean local, 
 IProgressMonitor monitor) throws CoreException;

の引数ですが、意味は以下の通りみたいです。

boolean force
ワークスペース内のリソースと、実際のファイルシステムに同期がとれてないときの挙動を指定
boolean local
実際のファイルシステムにもディレクトリを作成するか
IProgressMonitor? monitor
GUIのモニタを表示する場合にセットする

第一引数の指定で挙動がどう変わるかを、とりあえずワークスペースにフォルダがある場合・ない場合、ファイルシステム上にある場合・ない場合でまとめてみました。どうもこうなってるみたいです。

localがtrueの場合

ファイルシステム上にあるない
ワークスぺース上にあるないあるない
force = true例外ワークスペースに作成。
ファイルシステム上はなにもしない
例外作成する
force = false例外例外例外作成する

ファイルシステム上になくて、ワークスペース上にある場合、force=trueならファイルシステム上にファイルを作成するかと思ったのですが、例外が発生しましたね。

localがfalseの場合

ファイルシステム上にあるない
ワークスぺース上にあるないあるない
force = true例外ワークスペースにだけ作成例外ワークスペースにだけ作成
force = false例外例外例外ワークスペースにだけ作成

ようするにlocalがfalseの場合、ファイルシステム上には何も反映させないようですね。

まあワークスペースとファイルシステムが同期がとれてない場合には何もしない方がよいので、通常はforceフラグはfalseにしておいたほうがよいですね。localフラグに関してはtrueにしておかないとファイルシステム上に反映されないのでtrueがよいですね。

ファイルを作成する

次にファイルです。ファイル作成時はファイルの中身を渡してあげなくちゃいけないのですが、それにはファイルのストリームを渡してあげる必要があります。ファイルを作成するメソッド

public void create(InputStream source, boolean force,
 IProgressMonitor monitor) throws CoreException;

の引数InputStream?ですね。通常ファイルの内容からStringを作成しByteArrayInputStream?を作成すればよいと思います。以下のような感じですね。

String contents = "Hello World."; <-ファイルの中身
InputStream is = new ByteArrayInputStream(contents.getBytes());

ディレクトリの場合と同様、挙動を調べてみました。

ファイルシステム上にあるない
ワークスぺース上にあるないあるない
force = true例外ワークスペース上に作成し、
ファイルシステム上も上書きする
例外作成する
force = false例外例外例外作成する

あれ、でもこれだと普通にファイルを上書きすることができないですね。一応

file.delete(false, null);

を呼んでワークスペースとファイルシステムからファイルを消して、んで作成ってやればできますが、きっと上書きのメソッドがあると思います。残念時間切れ。

Javaソースコードから、対応するリソースを取得する

JDTまわりをやってて、IResource系にアクセスできるのかなあと思ってたら、ありました。

// ソースコードに対応するファイルのIResource
IResource resource = cu.getCorrespondingResource();

対応するIResourceが取得できます。

コンテンツ一覧

'Eclipse/プラグイン開発のTIPS集/ワークスペースのリソースを取り扱う/' には、下位層のページがありません。

関連リンク


この記事は

選択肢 投票
おもしろかった 11  
そうでもない 0  
  • 削除 -- 2014-12-25 (木) 16:38:20

Top / Eclipse / プラグイン開発のTIPS集 / ワークスペースのリソースを取り扱う

現在のアクセス:38989


添付ファイル: fileIResource.png 612件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2014-12-25 (木) 16:40:51 (1365d)