【问题标题】:How expensive is File.exists in JavaJava 中的 File.exists 有多贵
【发布时间】:2011-09-13 08:27:06
【问题描述】:

我想知道File.exists() 是如何工作的。我不太了解文件系统的工作原理,所以我应该先从那里开始阅读。

但对于快速的预信息:

调用File.exists() 是否是文件系统的单个操作,如果该路径和文件名已在某个日志中注册?还是操作系统获取目录的内容,然后扫描它以查找匹配项?

我认为这将取决于文件系统,但也许所有文件系统都使用快速方法?

我不是在谈论网络和磁带系统。让我们把它保存到 ntfs、extX、zfs、jfs :-)

【问题讨论】:

  • 日志文件系统与其他文件系统完全不同。
  • 这将是非常文件系统依赖。当您访问 NFS 或 SMB 文件共享上的文件时,可能涉及建立网络连接。如果底层光盘已断电,您将不得不等待它启动(如果它是光驱则更糟)。哎呀,在某些情况下(例如分层存储),它可能涉及加载磁带并且实际上需要几分钟!

标签: java file-io directory operating-system filesystems


【解决方案1】:

测量必要的时间,看看自己。正如你所说,它完全依赖于文件系统

        long t1 = System.currentTimeMillis();
        ...Your File.exists call
        long t2 = System.currentTimeMillis();
        System.out.println("time: " + (t2 - t1) + " ms");

你会发现它总是会给你不同的结果,因为它还取决于你的操作系统缓存数据的方式、它的负载等。

【讨论】:

  • 这几乎完全取决于是否需要磁盘访问,在这种情况下,您的磁盘速度(以及它是否繁忙)将是最重要的。如果您在文件在缓存中时进行测试,最好使用 System.nanoTime() 因为它通常是亚毫秒。
  • System.currentTimeMillis() 甚至不一定给你毫秒分辨率的时间。 ://
  • NanoTime 绝对更精确!仍然 currentTimeMillis 也可能给你很大的想法。也可以在测量之前将系统负载系数插入方程,但结果总是近似的。记住:如果不以某种方式改变它,你就无法观察实验......
  • 这并不完全取决于 FS 的实现,而是取决于操作系统中文件系统的缓存策略。如果目录被缓存并且文件或目录最近被使用过,您可以获得更快的响应。
  • 为什么你将long 自动装箱到Long 只是为了在减法期间将其转换回long
【解决方案2】:

如果第一次执行此操作完全取决于文件系统。这是由操作系统完成的,Java 没有任何作用。

就性能而言,在所有情况下都需要读取磁盘。这通常需要 8-12 毫秒。 @Sven 指出一些存储可能会变慢,但在性能很重要的情况下这种情况相对较少。如果这是一个网络文件系统,您可能会有额外的延迟(通常相对较小,但取决于您的网络延迟)。

相比之下,操作系统和 Java 所做的一切都非常短。

但是,如果您反复检查文件是否存在,则可能不需要磁盘访问,因为可以缓存信息,在这种情况下是操作系统占用的时间和资源。 File.exists() 创建的这些对象中最大的一个(你不会认为它会)但是它在每次调用创建大量对象时对文件名进行编码。如果你把 File.exists() 放在一个紧密的循环中,它每秒会产生 400MB 的垃圾。 :(

通过跟踪您对文件系统所做的所有更改,日志文件系统的工作方式有所不同,但它们不会改变您读取文件系统的方式。

【讨论】:

    【解决方案3】:

    大部分与文件相关的操作都不是在 Java 中执行的;存在本机代码来执行这些活动。实际上,完成的大部分工作取决于FileSystem 对象的性质(即支持File 对象)以及操作系统中本机IO 操作的底层实现。

    为了清楚起见,我将介绍 OpenJDK 6 中的实现案例。 File.exists() 实现将实际检查推迟到 FileSystem 类:

    public boolean exists() {
        ... calls to SecurityManager have been omitted for brevity ...
        return ((fs.getBooleanAttributes(this) & FileSystem.BA_EXISTS) != 0);
    }
    

    FileSystem 类是抽象的,所有支持的文件系统都有一个实现:

    package java.io;
    
    
    /**
     * Package-private abstract class for the local filesystem abstraction.
     */
    
    abstract class FileSystem
    

    注意包的私有性质。 Java 运行时环境将提供扩展 FileSystem 类的具体类。在 OpenJDK 实现中,有:

    • java.io.WinNTFileSystem,用于 NTFS
    • java.io.Win32FileSystem,用于 FAT32
    • java.io.UnixFileSystem,用于 *nix 文件系统(这是一个职责非常广泛的类)。

    以上所有类都委托给本机代码,用于getBooleanAttributes 方法。这意味着在这种情况下,性能不受托管(Java)代码的限制;文件系统的实现以及所进行的本机调用的性质对性能有更大的影响。

    更新 #2

    基于更新的问题 -

    我不是在谈论网络和磁带系统。让我们把它保存到 ntfs、extX、zfs、jfs

    好吧,那仍然没关系。不同的操作系统会以不同的方式实现对不同文件系统的支持。例如,Windows 中的 NTFS 支持将不同于 *nix 中的支持,因为除了通过驱动程序与设备通信外,操作系统还必须进行簿记。并非所有工作都在设备中完成。

    在 Windows 中,您几乎总能找到 file system filter drivers 的概念,它管理与其他文件系统过滤器驱动程序或文件系统通信的任务。这是支持各种操作所必需的;一个例子是使用过滤器驱动来拦截 IO 调用。

    在 *nix 中,您将拥有 stat() 系统调用,它将执行读取文件描述符的 inode 信息的必要活动。

    【讨论】:

      【解决方案4】:

      它在任何现代机器上都非常快,我的测试显示在我的 2013 Mac w/SSD 上为 0.0028 毫秒(2.8 微秒)

      在 307 毫秒内创建 1,000 个文件,每个文件 0.0307 毫秒

      1,000 .exists() 在 28 毫秒内完成,每个文件 0.0028 毫秒

      这是一个在 Groovy (Java) 中的测试

      def index() {
          File fileWrite
      
          long start = System.currentTimeMillis()
      
          (1..1000).each {
              fileWrite = new File("/tmp/fileSpeedTest/${it}.txt")
              fileWrite.write('Some nice text')
          }
          long diff = System.currentTimeMillis() - start
          println "1,000 files created in $diff millis, ${diff/10000.0} millis per file"
      
      
      
          start = System.currentTimeMillis()
          (1..1000).each {
              fileWrite = new File("/tmp/fileSpeedTest/${it}.txt")
              if ( ! fileWrite.exists() )
                  throw new Exception("where's the file")
          }
          diff = System.currentTimeMillis() - start
          println "1,000 .exists()   done in  $diff millis, ${diff/10000.0} millis per file"
      
      }
      

      【讨论】:

        猜你喜欢
        • 2010-12-15
        • 2011-09-23
        • 2013-10-18
        • 1970-01-01
        • 2016-08-26
        • 2010-12-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多