Как проверить существование файла в Java
Что проверяют
Знаете ли вы NIO.2 и его подводные камни, а не только new File(name).exists(). Интервьюер ждёт разницу между «файла нет» и «выяснить не удалось», понимание симлинков и гонки между проверкой и действием. Следом часто спрашивают, нужна ли тут проверка вообще.
Как отвечать
Современный способ: Files.exists(Path.of("data", "report.csv")). Path.of появился в Java 11, до него то же делал Paths.get. Что важно знать:
Files.existsиFiles.notExists: не бросаютIOExceptionи не взаимоисключающие. Если нет прав на каталог, оба вернутfalse, то есть результат неизвестен;- тип объекта:
existsвернётtrueи для каталога. Если нужен именно файл, естьFiles.isRegularFile, для правFiles.isReadableиFiles.isWritable; - симлинки: по умолчанию ссылка разыменовывается, и битая ссылка даёт
false. СLinkOption.NOFOLLOW_LINKSпроверяется сама ссылка; - относительный путь: считается от рабочего каталога процесса (
user.dir), а не от расположения класса или jar; - ресурсы внутри jar: это не файлы, их ищут через
getResourceилиgetResourceAsStream.
Главный инженерный момент: проверка и последующее действие не атомарны. Между exists и открытием файл могут удалить или создать. Поэтому часто правильнее сразу выполнить операцию и обработать исключение: Files.newBufferedReader бросит NoSuchFileException, а Files.createFile бросит FileAlreadyExistsException, если файл уже есть, и это атомарная проверка вместе с созданием.
Где спотыкаются
Оборачивают Files.exists в try/catch (IOException e). Метод это проверяемое исключение не бросает, и компилятор такой код не пропустит.
Трактуют !Files.exists(path) как «файла точно нет» и, например, пытаются создать его там, где просто нет доступа.
Пишут «проверил, потом прочитал» в коде, который работает с общими каталогами или из нескольких потоков, и получают редкие падения, которые не воспроизводятся локально.