プラグインからEclipseのワークスペース上のリソースを操作する方法をまとめます。
Eclipseのワークスペース関連のAPIは
のような構成となっています。これらへの参照を取得して、そのオブジェクトのメソッドを呼び出してワークスペースを操作するわけですね。
あ、これらの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
というインタフェース(とそのサブインタフェース)を実装しています。以下のような構成ですね。
プロジェクト内のリソースは
↓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 ファイルだ
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;
の引数ですが、意味は以下の通りみたいです。
第一引数の指定で挙動がどう変わるかを、とりあえずワークスペースにフォルダがある場合・ない場合、ファイルシステム上にある場合・ない場合でまとめてみました。どうもこうなってるみたいです。
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);
を呼んでワークスペースとファイルシステムからファイルを消して、んで作成ってやればできますが、きっと上書きのメソッドがあると思います。残念時間切れ。
JDTまわりをやってて、IResource系にアクセスできるのかなあと思ってたら、ありました。
// ソースコードに対応するファイルのIResource IResource resource = cu.getCorrespondingResource();
対応するIResourceが取得できます。
'Eclipse/プラグイン開発のTIPS集/ワークスペースのリソースを取り扱う/' には、下位層のページがありません。
この記事は
現在のアクセス:48167