Любой верный способ проверить существование файла в Linux NFS? - PullRequest
1 голос
/ 22 сентября 2011

Я работаю над Java-программой, требующей проверки существования файлов.

Что ж, достаточно просто, код использует вызовы File.exists () для проверки существования файла. И проблема у меня заключается в том, что он сообщает о ложном срабатывании. Это означает, что файл на самом деле не существует, но существует () метод возвращает значение true. Не было зафиксировано ни одного исключения (по крайней мере, исключение, например «устаревший дескриптор NFS»). Программе даже удалось прочитать файл через InputStream, получив 0 байт, как и ожидалось, и все же не исключение. Целевым каталогом является Linux NFS. И я на 100% уверен, что искомый файл никогда не существует.

Я знаю, что для java.io.File.exists () существуют известные ошибки (своего рода ограничение API). Поэтому я добавил еще один способ, проверив существование файла с помощью команды Linux "ls". Вместо вызова File.exists () код Java теперь запускает команду Linux для «ls» целевого файла. Если код выхода равен 0, файл существует. В противном случае файл не существует.

Количество раз, когда проблема решается, кажется, уменьшено с введением трюка, но все еще появляется. Опять же, нигде не было зафиксировано никаких ошибок (на этот раз stdout). Это означает, что проблема настолько серьезна, что даже собственная команда Linux не будет исправлена ​​в течение 100% времени.

Итак, есть пара вопросов:

  1. Я полагаю, что хорошо известная проблема Java в File.exists () связана с сообщением о ложном отрицании. Где сообщалось, что файл не существует, но на самом деле существует. Поскольку API не выдает IOException для File.exists (), он решает проглотить исключение в случае сбоя при вызове базовых собственных функций ОС, например. Тайм-аут NFS. Но тогда это не объясняет ложный положительный случай, который я имею, учитывая, что файл никогда не существует. Любой бросок на этом?
  2. Насколько я понимаю, в Linux "ls" код выхода: 0 означает, что файл эквивалентен. Это понимание неправильно? Справочная страница "ls" не совсем понятна при объяснении значения кода выхода: статус выхода равен 0, если все в порядке, 1, если небольшие проблемы, 2, если серьезные проблемы.
  3. Хорошо, вернемся к теме. Любой верный способ проверить существование файла с Java на Linux? Прежде чем мы увидим JDK7 с официально выпущенным NIO2.

Спасибо:)

Ответы [ 3 ]

0 голосов
/ 12 октября 2012

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

Единственный безопасный способ определить, существует ли файл и можно ли из него прочитать, - это фактически прочитать данные из файла. Независимо от файловой системы - локальной или удаленной. Причиной является состояние гонки, которое может возникнуть сразу после получения успеха от checkAccess(path): проверьте, затем откройте файл, и вы обнаружите, что он внезапно не существует. Какой-то другой поток (или другой удаленный клиент), возможно, удалил его или приобрел монопольную блокировку. Так что не беспокойтесь о проверке доступа, а попробуйте прочитать файл. Трата времени на бег ls только облегчает установку окна состояния гонки.

0 голосов
/ 21 апреля 2014

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

Проблема возникает, например, использование Samba на OSX Mavericks. Возможная причина объясняется утверждением в: http://appleinsider.com/articles/13/06/11/apple-shifts-from-afp-file-sharing-to-smb2-in-os-x-109-mavericks

Агрессивно кэширует свойства файлов и папок и использует оппортунистическую блокировку для обеспечения лучшего кэширования данных.

Пожалуйста, найдите ниже контрольный файл, который фактически попытается прочитать несколько байтов и принудительно установить истинный доступ к файлу, чтобы избежать неправильного поведения кэширования ...

JUnit test:

/**
 * test file exists function on Network drive replace the testfile name and ssh computer
     * with your actual environment
 * @throws Exception
 */
@Test
public void testFileExistsOnNetworkDrive() throws Exception {
    String testFileName="/Volumes/bitplan/tmp/testFileExists.txt";
    File testFile=new File(testFileName);
    testFile.delete();
    for (int i=0;i<10;i++) {
        Thread.sleep(50);
        System.out.println(""+i+":"+OCRJob.checkExists(testFile));
        switch (i) {
        case 3:
            // FileUtils.writeStringToFile(testFile, "here we go");
            Runtime.getRuntime().exec("/usr/bin/ssh phobos /usr/bin/touch "+testFileName);
            break;
        }
    }
}

checkExists исходный код:

/**
 * check if the given file exists
 * @param f
 * @return true if file exists
 */
public static boolean checkExists(File f)  {
    try {
        byte[] buffer = new byte[4];
        InputStream is = new FileInputStream(f);
        if (is.read(buffer) != buffer.length) { 
            // do something 
        }
        is.close();
        return true;
    } catch (java.io.IOException fnfe) {

    }
    return false;
}
0 голосов
/ 22 сентября 2011

JDK7 был выпущен несколько месяцев назад.Существуют методы notExists в классе Files, но они возвращают логическое значение, а не выдают исключение.Если вы действительно хотите исключение, используйте FileSystems.getDefault (). Provider (). CheckAccess (путь), и оно выдаст исключение, если файл не существует.

...