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