虚拟文件系统

走着路睡觉大约 6 分钟

虚拟文件系统

虚拟文件系统 ( Virtual File System:缩写为VFS) 是 IntelliJ 平台的一个组件,它封装了虚拟文件 的大部分操作。

VFS主要有以下功能:

  • 用统一的API来处理不同来源的文件(例如:硬盘上的文件,jar包中的文件,http文件等)

  • 监控文件的修改,为文件提供版本控制

  • 管理文件的持久化操作

在后2个功能里,VFS管理了持久化文件的一个快照。快照里只存储了通过VFS API请求过的文件,并且能同步更新到硬盘上。

快照是应用级的,不是项目级的,所以即使一个文件(例如。JDK中的类)被多个项目引用了,在VFS系统里也只会存储一份

所有VFS的操作都会经过快照

通过 VFS 请求一些数据,如果快照中的数据是可用的,将直接返回快照中的数据,如果快照中没有可用数据,将会从磁盘中加载并存储到VFS 里。仅当访问特定信息时,快照才会存储文件的内容和目录中的文件列表。否则,只存储文件元数据,如名称、长度、时间戳、属性等。

提示

在 IntelliJ Platform UI中显示的文件内容来源于快照,这将导致显示中的内容和硬盘上的内容并不会永远完全一致。例如:某些文件被删除了,但是IntelliJ Platform 还没有删除它的快照,所以还能访问该文件。

在磁盘刷新操作(refresh operations)的时候快照会进行 同步 更新。所有通过VFS的写入操作都是同步 的,保存的时候会立即更新到硬盘上。

IntelliJ Platform或插件在调用刷新操作(refresh operations)时,刷新操作(refresh operations)才会将硬盘内容和VFS 的相关内容进行同步。 也就是说,当IDE 在运行的时候,硬盘上的文件被修改了。VFS 并不会立即更新,VFS 会在下一次刷新操作(refresh operations)的时候更新文件,以及跟该文件关联的其它文件。

IntelliJ Platform会在 IDE 启动的时候异步 刷新项目内容。默认情况下,用户从其它应用切换到IDE 的时候会进行刷新操作。用户也可以通过 Settings/Preferences | Appearance & Behavior | System Settings | Synchronize external changes[...] 关闭默认刷新操作,如下图:

在Windows, Mac, 和 Linux系统上,会启动一个监控进程来监控文件的修改并通知IntelliJ Platform。如果监控进程可用,IntelliJ Platform 刷新操作只会更新通知的文件,如果监控进程不可用,刷新操作会遍历更新相关的所有文件和文件夹

提示

内部操作 Tools | Internal Actions | VFS 可以看到VFS的相关信息

刷新操作是依据时间戳进行对比的。如果文件的内容已更改,但其时间戳保持不变,则 IntelliJ Platform 将不会更新内容。

快照不支持删除某个文件。如果加载过某个文件,只有从硬盘上删除这个文件,并且它的父目录调用了刷新操作,才会从快照中删除该文件,否则这个文件会一直保存在快照中。

VFS 不会加载在 Settings/Preferences | Editor | File TypesProject Structure | Modules | Sources | Excluded 忽略的文件和文件夹。但是当应用程序代码访问它们的时候,VFS 会加载它们。

IntelliJ Platform IDE 运行期间,大部分的 VirtualFile 和硬盘上的文件内容一样,拥有相同的 hashCode,共享用户数据。

同步和异常刷新

从调用者的角度看,刷新操作分为同步和异步。实际上,刷新操作是按照自己的策略执行。

同步刷新操作会阻塞线程直到刷新操作(刷新操作大部分情况在另外的线程进行)完成。

任何线程都可以进行同步刷新和异步刷新。但是后台线程在进行读取操作时,不能调用刷新操作,因为会引起死锁。详情可查看文档:线程规则

相同的线程要求也适用于 LocalFileSystem.refreshAndFindFileByPath()open in new window 等函数,如果在快照中找不到指定路径的文件,则会刷新指定路径的内容

强烈推荐使用异步刷新操作。如果需要在刷新操作完成后执行业务逻辑,可以在 RefreshQueue.createSession()open in new windowVirtualFile.refresh()open in new window 方法的 postRunnable 参数里执行业务逻辑

使用同步刷新操作可能会引起死锁

虚拟文件系统事件

VFS 进行刷新操作、用户进行操作等,都会发布VFS 事件。VFS事件一般都由写入操作和dispatch thread 触发。

想要监听VFS 事件,最好的方式是实现 BulkFileListeneropen in new window 接口,并在接口中订阅 VirtualFileManager.VFS_CHANGESopen in new window 主题。 在IntelliJ Platform 2019.2 及以后的版本里,也可以使用非阻塞监听器 AsyncFileListeneropen in new window ,如何实现监听功能请查看文档 订阅VFS文件修改事件

注意

VFS 监听器是应用级的,会接收所有项目里发生的文件修改事件。可以通过 ProjectFileIndex.isInXX()open in new window 对事件进行过滤

每一次文件修改前、文件修改后都会发送 VFS 事件, 可以从文件修改前发送的事件中获取文件未修改时的内容。需要注意的是通过VFS 修改文件时,当刷新操作完成,并更新到磁盘上后,才会发送文件修改完成事件。所以当你收到文件删除事件(beforeFileDeletion)时,文件已经被删除了。但是,该文件依然存在快照中,你可以使用VFS API从快照中获取文件的最后的内容。

请注意,刷新操作只针对快照加载过的文件触发的事件。例如:如果你加载一个文件夹为 VirtualFile,但是没有使用 VirtualFile.getChildren() 方法加载它的子文件,如果在该文件夹下面创建了某个文件,你可能收不到该文件创建( fileCreated )事件。

如果你使用了 VirtualFile.findChild() 加载了文件夹下面的某一个文件,你会收到该文件的所有修改事件。但是你收不到同一个文件夹下面的其它事件,例如 created,deleted等事件

上次编辑于:
贡献者: zhaojingbo
Loading...