Проверьте, существует ли файл java.nio

#java #filesystems #java.nio.file

#java #файловые системы #java.nio.file

Вопрос:

Я пытаюсь проверить, существует ли файл, но он не работает.

 FileSystem fs = FileSystems.getDefault();
Path p = fs.getPath(fileName);

if(!Files.exists(p)) {
    create(fileName);
} else {
    throw new ConflictException(String.format("File already exist."));
}
  

Проблема в том, что даже файл существует с тем же именем файла, который он вводит внутрь if statement и переходит к create методу, и когда дело доходит до создания файла, он возвращает исключение, что файл уже существует.
В чем может быть проблема и возможное решение для проверки, существует ли файл / каталог, если я использую файловую систему?

Ответ №1:

Вы делаете это неправильно.

Общий принцип при работе в средах, подверженных внешним изменениям, таких как файловые системы, вы просто не можете выполнить проверку и действие. Весь этот принцип нарушается в такой среде, и вы делаете это здесь:

Вы проверяете, существует ли файл, а затем, в зависимости от результата, выбираете действие. Это проверка и действие и не работает.

В конце концов, что, если «ответ» на вашу проверку изменится между проверкой и действием? Это даже не обязательно должен быть другой поток внутри вашей собственной виртуальной машины, это может быть другой процесс. Вы также не можете синхронизировать что-либо, чтобы выполнить эту работу «безопасно».

Нет, правильный принцип — действовать, а затем проверять. Выполните операцию «создайте этот файл, но только если его там еще нет», атомарно, и разберитесь с последствиями, то есть разберитесь с ошибкой впоследствии, если файл уже существовал.

К счастью, Java nio поддерживает это (старый File API этого не делает, не используйте это). Наконец, нет необходимости просматривать содержимое файловой системы, если вы используете файловую систему по умолчанию. Однако, если это было сделано только для упрощения вопроса, это работает так же хорошо с пользовательской файловой системой:

 Path p = Paths.get(fileName);

try {
    try (var out = Files.newOutputStream(p, StandardOpenOption.CREATE_NEW)) {
       // write your file here
    }
} catch (FileAlreadyExistsException e) {
    throw new ConflictException(String.format("File already exists", e);
}
// CREATE_NEW is the magic voodoo here: That tells java:
// do this ONLY if you make a new file, otherwise don't do it, atomically.
  

хотя обратите внимание, что FAEException работает как есть, поэтому я не уверен, что вам обязательно нужно обернуть это в conflictexception — это имеет смысл только в том случае, если этот API абстрагировался от представления о том, что вы делаете это с файловой системой (вы не включили имя метода или javadoc в свою вставку, поэтому яне могу сказать).

Если вам не нужно ничего записывать в файл, вам не нужно newOutputStream , вы можете просто использовать:

 Path p = Paths.get(fileName);

try {
    Files.createFile(p);
} catch (FileAlreadyExistsException e) {
    throw new ConflictException(String.format("File already exists", e);
}
// Files.createFile implies CREATE_NEW already; it either makes
// the file and returns, or doesn't and throws FAEEx.
  

Комментарии:

1. Знаем ли мы, что другие процессы могут создавать файлы? Если их создает только программа kavkax, атомарная проверка не решит проблему.

2. @VGR … но это решило бы проблему. проверка-затем-действие отлично работает в ситуации A и завершается сбоем в ситуации B. проверка-затем-проверка отлично работает в A, а также отлично работает в B, что делает его строго превосходным. (A = нет других процессов, вмешивающихся в файловую систему, И нет других потоков, B = есть другие процессы и / или потоки, которые могут создать этот файл).

3. Для контекста, похоже, что, возможно, проблема kavkax больше связана, например, с неправильным именем файла в первую очередь. Однако нет особого смысла помогать кому-либо отлаживать код, который принципиально не способен выполнять работу, для которой он предназначен; лучше сначала хотя бы настроить его так, чтобы он мог, по крайней мере, выполнять работу, для которой он предназначен, а ЗАТЕМ, если после перезаписи все еще остаются проблемы, исправить их.