web-dev-qa-db-ja.com

File.existsのコストはJava

File.exists()がどのように機能するのか疑問に思っています。私はファイルシステムがどのように機能するかをあまり知らないので、最初にそこで読み始めるべきかもしれません。

しかし、簡単な事前情報については:

そのパスとファイル名がジャーナルに登録されている場合、File.exists()の呼び出しはファイルシステムの単一のアクションですか?または、OSはディレクトリのコンテンツを取得し、それをスキャンして一致するものを探しますか?

これはファイルシステムに依存すると思いますが、おそらくすべてのファイルシステムがクイックアプローチを使用していますか?

私はネットワークとテープシステムについて話しているのではありません。 ntfs、extX、zfs、jfsに保持しましょう:-)

32
Franz Kafka

この操作を初めて実行する場合、ファイルシステムに完全に依存します。これはOSによって行われ、Javaは何の役割も果たしません。

パフォーマンスの観点から、すべての場合にディスクへの読み取りが必要です。これには通常8〜12ミリ秒かかります。 @Svenは、一部のストレージが遅くなる可能性があることを指摘していますが、パフォーマンスが重要な場合、これは比較的まれです。これがネットワークファイルシステムの場合、追加の遅延が発生する可能性があります(通常は比較的小さいですが、ネットワークの待ち時間によって異なります)。

他のすべてのOSとJavaが行うことは、比較すると非常に短いです。

ただし、ファイルが繰り返し存在することを確認する場合は、情報をキャッシュできるため、ディスクアクセスは必要ない場合があります。この場合、OSにかかる時間とリソースです。 File.exists()が作成するこれらのオブジェクトの中で最大のものの1つですが(そうなるとは思わないでしょう)、多くのオブジェクトを作成するすべての呼び出しでファイルの名前をエンコードします。 File.exists()をタイトなループに入れると、1秒あたり400MBのガベージが発生する可能性があります。 :(

ジャーナリングファイルシステムは、ファイルシステムに加えたすべての変更を追跡することで動作が異なりますが、ファイルシステムの読み取り方法は変更されません。

15
Peter Lawrey

必要な時間を測定し、自分自身を見てください。あなたが言うようにそれは絶対にファイルシステムに依存します

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

OSがデータをキャッシュする方法や負荷などにも依存するため、常に異なる結果が得られることがわかります。

16
Costis Aivalis

ファイル関連の操作のほとんどはJavaでは実行されません。これらのアクティビティを実行するためのネイティブコードが存在します。実際には、行われる作業のほとんどは、FileSystemオブジェクト(つまり、Fileオブジェクトをサポートする)の性質と、ネイティブIO = OSでの操作。

わかりやすくするために、OpenJDK6での実装の事例を紹介します。 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では、ほとんどの場合、他のファイルシステムフィルタードライバーまたはファイルシステムとの通信タスクを管理する ファイルシステムフィルタードライバー の概念があります。これは、さまざまな操作をサポートするために必要です。 1つの例は、IO呼び出しをインターセプトするアンチウイルスエンジンおよびその他のソフトウェア(オンザフライ暗号化および圧縮製品)用のフィルタードライバーの使用です。

* nixには、ファイル記述子のiノード情報を読み取るために必要なアクティビティを実行する stat() システム呼び出しがあります。

8
Vineet Reynolds

最新のマシンでは超高速です。私のテストでは、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"

}
0
Travis May