// 一覧用テンプレート #topicpath ---- #contents プラグインからEclipseのワークスペース上のリソースを操作する方法をまとめます。 **全体の構成 [#s9356f95] Eclipseのワークスペース関連のAPIは -ワークスペース全体を表すorg.eclipse.core.resources.IWorkspaceRoot -その下の各プロジェクトorg.eclipse.core.resources.IProject -プロジェクト内のリソースorg.eclipse.core.resources.IResource のような構成となっています。これらへの参照を取得して、そのオブジェクトのメソッドを呼び出してワークスペースを操作するわけですね。 あ、これらのAPIを使用するには org.eclipse.core.resources を依存関係に追加してください。 **ワークスペースの参照を取得する [#k467344b] IWorkspace workspace = ResourcesPlugin.getWorkspace(); IWorkspaceRoot root = workspace.getRoot(); これでワークスペースへの参照を取得することができます。このIWorkspaceRoot から各プロジェクトへの参照を取得することができます。 **プロジェクトへの参照を取得する [#t157b35f] IWorkspaceRoot root = workspace.getRoot(); IProject[] projects = root.getProjects(); これで現在起動しているワークスペース内のプロジェクトを配列で取得することできました。また、 IProject project = root.getProject([プロジェクト名の文字列]); などとしてプロジェクト名指定で参照を取得することもできます。 **プロジェクトを作成する [#t157b35f] 先のメソッドでプロジェクトを取得することができましたが、プロジェクトを作成するには以下のようにします。 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を渡してますが。 **プロジェクト内の各リソース [#ea1f2338] プロジェクト内のリソースはすべて org.eclipse.core.resources.IResource というインタフェース(とそのサブインタフェース)を実装しています。以下のような構成ですね。 #ref(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以外の方法 [#f9d8913b] 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 です。でもこれだと一階層下のリソースしか取得できないですね。ディレクトリツリーを末端まで走査するには、自前で再帰的に処理する必要がありそうですね。 **ディレクトリを作成する [#s73ab009] プロジェクト内にディレクトリやファイルを作成する方法です。ディレクトリの作成は -プロジェクトを取得 -プロジェクトのルートから相対的なパスを取得 -実際に生成する といった手順となります。たとえばプロジェクト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の場合 |BGCOLOR(#CCFFFF):LEFT:ファイルシステム上に|>|BGCOLOR(#CCFFFF):CENTER:ある|>|BGCOLOR(#CCFFFF):CENTER:ない| |BGCOLOR(#CCFFFF):LEFT:ワークスぺース上に|BGCOLOR(#CCFFFF):CENTER:ある|BGCOLOR(#CCFFFF):CENTER:ない|BGCOLOR(#CCFFFF):CENTER:ある|BGCOLOR(#CCFFFF):CENTER:ない| |BGCOLOR(#CCFFFF):LEFT:force = true|LEFT:例外|LEFT:ワークスペースに作成。&br;ファイルシステム上はなにもしない|LEFT:例外|LEFT:作成する| |BGCOLOR(#CCFFFF):LEFT:force = false|LEFT:例外|LEFT:例外|LEFT:例外|LEFT:作成する| ファイルシステム上になくて、ワークスペース上にある場合、force=trueならファイルシステム上にファイルを作成するかと思ったのですが、例外が発生しましたね。 localがfalseの場合 |BGCOLOR(#CCFFFF):LEFT:ファイルシステム上に|>|BGCOLOR(#CCFFFF):CENTER:ある|>|BGCOLOR(#CCFFFF):CENTER:ない| |BGCOLOR(#CCFFFF):LEFT:ワークスぺース上に|BGCOLOR(#CCFFFF):CENTER:ある|BGCOLOR(#CCFFFF):CENTER:ない|BGCOLOR(#CCFFFF):CENTER:ある|BGCOLOR(#CCFFFF):CENTER:ない| |BGCOLOR(#CCFFFF):LEFT:force = true|LEFT:例外|LEFT:ワークスペースにだけ作成|LEFT:例外|LEFT:ワークスペースにだけ作成| |BGCOLOR(#CCFFFF):LEFT:force = false|LEFT:例外|LEFT:例外|LEFT:例外|LEFT:ワークスペースにだけ作成| ようするにlocalがfalseの場合、ファイルシステム上には何も反映させないようですね。 まあワークスペースとファイルシステムが同期がとれてない場合には何もしない方がよいので、通常はforceフラグはfalse西手負いたほうがよいですね。localフラグに関してはtrueにしておかないとファイルシステム上に反映されないのでtrueがよいですね。 **ファイルを作成する [#z915a5c7] 次にファイルです。ファイル作成時はファイルの中身を渡してあげなくちゃいけないのですが、それにはファイル内のデータをbyte[]にして渡してあげる必要があります。具体的には public void create(InputStream source, boolean force, IProgressMonitor monitor) throws CoreException; メソッドのInputStreamの事ですね。 ディレクトリの場合と同様、挙動を調べてみました。 |BGCOLOR(#CCFFFF):LEFT:ファイルシステム上に|>|BGCOLOR(#CCFFFF):CENTER:ある|>|BGCOLOR(#CCFFFF):CENTER:ない| |BGCOLOR(#CCFFFF):LEFT:ワークスぺース上に|BGCOLOR(#CCFFFF):CENTER:ある|BGCOLOR(#CCFFFF):CENTER:ない|BGCOLOR(#CCFFFF):CENTER:ある|BGCOLOR(#CCFFFF):CENTER:ない| |BGCOLOR(#CCFFFF):LEFT:force = true|LEFT:例外|LEFT:ワークスペース上に作成し、&br;ファイルシステム上も上書きする|LEFT:例外|LEFT:作成する| |BGCOLOR(#CCFFFF):LEFT:force = false|LEFT:例外|LEFT:例外|LEFT:例外|LEFT:作成する| あれ、でもこれだと普通にファイルを上書きすることができないですね。 **Javaソースコードから、対応するリソースを取得する [#v783dbb5] [[JDTまわりをやってて>Eclipse/プラグイン開発のTIPS集/Javaプロジェクトを操作する]]、IResource系にアクセスできるのかなあと思ってたら、ありました。 // ソースコードに対応するファイルのIResource IResource resource = cu.getCorrespondingResource(); 対応するIResourceが取得できます。 ***コンテンツ一覧 [#f5b87e5a] #ls2 ***関連リンク [#ee033052] -[[プラグインでリソースを扱う>http://www13.plala.or.jp/observe/PDE/PDEResources.html]] -Eclipse/プラグイン開発のTIPS集/Javaプロジェクトを操作する -Eclipse/プラグイン開発のTIPS集/ソースコードを解析するパーサASTParser -Eclipse/プラグイン開発のTIPS集/ソースコードを解析するパーサASTParser/TypeDeclaration ---- この記事は #vote(おもしろかった,そうでもない) #comment #topicpath SIZE(10){現在のアクセス:&counter;}