当平台核心正在运行并且资源插件是活动的时候, 工作区是由 IWorkspace 的实例表示的, 它提供用于访问它包含的资源的协议。IWorkspace 实例表示本地文件系统中相关联的文件和目录的集合。可以从 org.eclipse.core.resources 中的资源插件类访问工作区。
ResourcesPlugin.getWorkspace();
当资源插件未运行时,工作区单独存在于本地文件系统中, 用户可以通过标准的基于文件的工具来查看或处理工作区。让我们在说明资源插件 API 时看一下磁盘上工作区的外观。
安装平台 SDK 时,已将文件解压缩到您选择的目录中。我们将此目录称为平台根目录。此目录包含 plugins 目录以及其他目录。在平台根目录中,有一个 workspace 目录, 该目录用来保存由平台创建和处理的资源。如果查看 workspace 目录,将会看到工作区中存在的每个项目的不同子目录。在这些子目录中是每个项目包含的文件夹和文件。
如果示例中的 SDK 安装在 c:\MySDK 中, 则在 c:\MySDK\workspace 目录中,可以找到根据工作区的项目 MyWeb 和 MyServlet 命名的子目录。这些目录称为项目的内容目录。内容目录是用户创建项目时由平台创建的。
在项目的每个目录中,都会找到文件和文件夹, 其布局与它们在工作区的资源树中的布局完全相同。所有文件名都是一样的,并且无论从文件系统还是从工作区来访问,文件的内容都是相同的。不必奇怪。
C:\MySDK\workspace (工作区根目录)
.metadata\ (平台元数据目录)
MyWeb\ (MyWeb 的项目内容目录)
index.html
images\
logo.gif
MyServlet\ (MyServlet 的项目内容目录)
src\
main.java
bin\
main.class
main$$1.class
平台具有特殊 .metadata 目录,用来保存平台内部信息。工作区的 .metadata 目录被认为是一个“黑匣子”。有关工作区结构的重要信息(例如,项目的引用或者资源的特性)都存储在工作区的元数据部分, 并且应当只能由工具通过平台 API 来访问。决不能使用一般文件系统 API 来编辑或处理这些文件。
除了 .metadata 目录之外, 其他工具也可公平使用工作区目录中的文件夹和文件。文件和文件夹可以由非集成工具来处理,例如,文本编辑器和文件系统实用程序。唯一的问题就是当用户在工作台内部和外部编辑这些文件时都必须小心。(这与用户使用两个无关的独立工具来编辑文件没有区别。) 工作台提供了刷新操作来协调资源的工作区视图与文件系统的实际状态。
资源 API 允许用代码处理此资源树。下面,我们将考察一些代码片段,以便快速地了解资源 API。资源 API 是在 org.eclipse.core.resources 中的一系列接口中定义的。以下是所有资源类型的接口,例如 IProject、 IFolder 和 IFile。扩展公共协议是在 IResource 中定义的。我们还要利用 org.eclipse.core.runtime 接口 IPath, 它表示分段路径,例如资源或文件系统路径。
处理资源与使用 java.io.File 处理文件非常相似。API 是基于句柄的。当您使用 API 时,例如 getProject 或 getFolder, 将对资源返回句柄。 在您试图对句柄执行操作之前,不能保证或要求资源本身是存在的。如果期望资源存在,则可以使用 exists() 协议来确保资源存在。
要从插件中浏览工作区,我们必须首先获得 IWorkspaceRoot, 它表示工作区中的资源层次结构的顶部。
IWorkspaceRoot myWorkspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
一旦我们具有工作区根目录,就可以访问工作区中的项目。
IProject myWebProject = myWorkspaceRoot.getProject("MyWeb");
// 必要时打开
if (myWebProject.exists() && !myWebProject.isOpen())
myWebProject.open(null);
必须打开项目才能进行处理。打开项目时, 将从磁盘中阅读项目的结构,并创建项目的资源树的内存对象表示法。打开项目是一种显式操作,原因是每个打开的项目都会消耗内存来在内部表示资源树, 而打开的项目会参与各种资源有效期事件(例如,构建),这可能是一个漫长的过程。一般来说,不能访问关闭的项目,即使资源仍然存在于文件系统中,关闭的项目也将显示为空的。
您将注意到,当处理资源时,其中许多资源示例都传送 null 参数。许多资源操作都可能会花很长时间,足以使用进度报告和用户取消。如果代码具有用户界面,则您通常将传送 IProgressMonitor, 它允许资源插件在处理资源时报告进度,并且在必要时允许用户取消操作。现在,我们只传送 null,指示没有进度监视器。
一旦有打开的项目,我们就可以访问它的文件夹和文件,以及创建附加的文件夹和文件。在以下示例中,我们根据位于工作区外部的外部文件的内容来创建文件资源。
IFolder imagesFolder = myWebProject.getFolder("images");
if (imagesFolder.exists()) {
// 创建新文件
IFile newLogo = imagesFolder.getFile("newLogo.gif");
FileInputStream fileStream = new FileInputStream(
"c:/MyOtherData/newLogo.gif");
newLogo.create(fileStream, false, null);
fileStream.close();
}
在以上示例中,第一行获得图像文件夹的句柄。必须核实文件确实存在之后,才能对它执行任何有意义的操作。同样地,当我们获得文件 newLogo 时,在我们在最后一行创建文件之前, 句柄不能代表实际的文件。在此示例中,我们通过利用 logo.gif 的内容来填充文件来创建文件。
以下代码片段类似于前一代码片段, 只不过它是从初始徽标中复制 newLogo 文件, 而不是根据它的内容来创建新文件。
IFile logo = imagesFolder.getFile("logo.gif");
if (logo.exists()) {
IPath newLogoPath = new Path("newLogo.gif");
logo.copy(newLogoPath,
false, null);
IFile newLogo = imagesFolder.getFile("newLogo.gif");
...
}
最后,我们将创建另一个图像文件夹,并将新创建的文件移到该文件夹中。作为移动文件的附加效果,我们也对其进行了重命名。
...
IFolder newImagesFolder = myWebProject.getFolder("newimages");
newImagesFolder.create(false, true, null);
IPath renamedPath = newImagesFolder.getFullPath().append("renamedLogo.gif");
newLogo.move(renamedPath, false, null);
IFile renamedLogo = newImagesFolder.getFile("renamedLogo.gif");
许多资源 API 方法都包括一个 force 布尔标志, 它指定是否更新与本地文件系统中的相应文件不同步的资源。参见 IResource 以获取更多信息。
在样本资源树中,我们假定所有项目内容目录都在平台根目录下面的 workspace 目录中(C:\MySDK\workspace)。这是项目的缺省配置。然而,项目的内容目录可以重新映射为文件系统中的任何目录,甚至可能在另一磁盘驱动器上。
独立于其他项目映射项目的位置的能力允许用户将项目的内容存储在对项目和项目小组有意义的位置。项目的内容目录可视作“对外开放的”。这意味着用户可以通过使用工作台和插件,或者直接使用基于文件系统的工具和编辑器来创建、修改和删除资源。
资源路径名不是完整的文件系统路径。资源路径始终以项目的位置(通常为 workspace 目录)为基础。要获得指向资源的完整文件系统路径,必须使用 IResource.getLocation() 来查询它的位置。
可以通过使用 getLocation() 来查询特定资源的位置来确定该资源的文件系统位置。然而,不能使用 IProjectDescription.setLocation 来更改它的位置,因为该方法只是用于数据结构的简单 Setter。
当使用资源 API 来修改工作区的资源树时, 除了更新资源对象之外,还会更改文件系统中的文件。在平台的 API 外部发生的资源文件更改又如何?
在资源插件检测到资源的外部更改之前, 这些更改不会反映在工作区和资源对象中。客户机可以使用资源 API 来安静地协调工作区和资源对象与本地文件系统,不需要用户干预。用户始终可以在工作台的资源导航器视图中显式地强制执行刷新。
注意:资源 API 中的许多方法都包含一个强制参数, 该参数指定应该如何处理与文件系统不同步的资源。每种方法的“API 参考”都提供了有关此参数的特定信息。API 中的其他方法允许使用程序控制文件系统刷新, 例如,IResource.refreshLocal(int depth, IProgressMonitor monitor)。有关正确的用法和成本的信息, 参见 IResource。