Сколько стоит File.exists в Java - PullRequest
29 голосов
/ 12 июня 2011

Мне интересно, как работает File.exists(). Я не очень осведомлен о том, как работают файловые системы, поэтому мне, возможно, стоит сначала начать читать там.

Но для быстрой предварительной информации:

Является ли вызов File.exists() единственным действием для файловой системы, если этот путь и имя файла зарегистрированы в каком-либо журнале? Или ОС получает содержимое каталога, а затем сканирует его на предмет совпадений?

Полагаю, это будет зависеть от файловой системы, но, может быть, все файловые системы используют быстрый подход?

Я не говорю о сетевых и ленточных системах. Оставим это в формате ntfs, extX, zfs, jfs: -)

Ответы [ 4 ]

16 голосов
/ 12 июня 2011

Измерьте необходимое время и убедитесь сами. Как вы говорите, зависит от файловой системы .

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

Вы увидите, что он всегда будет давать разные результаты, поскольку это зависит также от того, как ваша ОС кэширует данные, от их загрузки и т. Д.

15 голосов
/ 12 июня 2011

То, как эта операция выполняется в первый раз, полностью зависит от файловой системы.Это делается операционной системой, и Java не играет никакой роли.

С точки зрения производительности, чтение на диск требуется во всех случаях.Обычно это занимает 8-12 мс.@ Свен указывает, что некоторые хранилища могут работать медленнее, но это относительно редко в тех случаях, когда важна производительность.У вас может быть дополнительная задержка, если это сетевая файловая система (обычно относительно небольшая, но это зависит от вашей сетевой задержки).

Все остальное, что делает ОС и Java, очень мало для сравнения.

Однако, если вы проверяете, что файл существует несколько раз, доступ к диску может не потребоваться, поскольку информация может кэшироваться, в этом случае время, которое занимает ОС и ресурсы.Один из самых больших из этих объектов File.exists () создает (вы бы не думали, что это произойдет), однако он кодирует имя файла при каждом вызове, создавая множество объектов.Если вы поместите File.exists () в узкий цикл, это может создать 400 МБ мусора в секунду.: (

Журналирование файловых систем работает по-разному, отслеживая все изменения, которые вы вносите в файловую систему, однако они не меняют способ чтения файловой системы.

8 голосов
/ 12 июня 2011

Большинство операций с файлами не выполняются в Java; для выполнения этих действий существует собственный код. В действительности большая часть выполняемой работы зависит от природы объекта FileSystem (который поддерживает объект File) и базовой реализации собственных операций ввода-вывода в ОС.

Для ясности я приведу пример реализации в 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

Ну, это все равно не имеет значения. Разные операционные системы будут реализовывать поддержку разных файловых систем по-разному. Например, поддержка NTFS в Windows будет отличаться от поддержки в * nix, потому что операционная система также должна будет нести свою долю бухгалтерии, помимо связи с устройствами через их драйверы; не вся работа выполняется в устройстве.

В Windows вы почти всегда найдете концепцию драйверов фильтра файловой системы , которая управляет задачей связи с другими драйверами фильтра файловой системы или файловой системой. Это необходимо для поддержки различных операций; В качестве примера можно привести использование драйверов фильтров для антивирусных ядер и другого программного обеспечения (продуктов шифрования и сжатия на лету), перехватывающих вызовы ввода-вывода.

В * nix у вас будет stat () , системный вызов, который выполнит необходимую операцию чтения информации inode для дескриптора файла.

0 голосов
/ 23 октября 2018

Это супер быстро на любой современной машине, мои тесты показывают 0,0028 миллисекунд (2,8 микросекунды) на моем Mac 2013 / SSD

1000 файлов, созданных с 307 миллисекундами, 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"

}
...