Looking for java Keywords? Try Ask4Keywords

Java Language Pitfall: тестирование файла перед попыткой его открыть.


пример

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

public static File getValidatedFile(String path) throws IOException {
    File f = new File(path);
    if (!f.exists()) throw new IOException("Error: not found: " + path);
    if (!f.isFile()) throw new IOException("Error: Is a directory: " + path);
    if (!f.canRead()) throw new IOException("Error: cannot read file: " + path);
    return f;
}

Вы можете использовать вышеупомянутый метод следующим образом:

File f = null;
try {
    f = getValidatedFile("somefile");
} catch (IOException ex) {
    System.err.println(ex.getMessage());
    return;
}
try (InputStream is = new FileInputStream(file)) {
    // Read data etc.
}

Первая проблема заключается в сигнатуре для FileInputStream(File) потому что компилятор по-прежнему настаивает на том, что мы поймаем IOException здесь или дальше по стеку.

Вторая проблема заключается в том, что проверки, выполняемые методом getValidatedFile , не гарантируют успеха FileInputStream .

  • Условия гонки: другой поток или отдельный процесс может переименовать файл, удалить файл или удалить доступ для чтения после возвращения getValidatedFile . Это приведет к « IOException » IOException без специального сообщения.

  • Есть те случаи, которые не охватываются этими тестами. Например, в системе с SELinux в режиме принудительного исполнения попытка чтения файла может завершиться неудачей, несмотря на то, что canRead() возвращает true .

Третья проблема заключается в том, что тесты неэффективны. Например, exists вызовы isFile и canRead , каждый из которых выполняет команду syscall для выполнения требуемой проверки. Затем открывается другой syscall, чтобы открыть файл, который повторяет те же проверки за кулисами.

Короче говоря, такие методы, как getValidatedFile , ошибочны. Лучше просто попытаться открыть файл и обработать исключение:

try (InputStream is = new FileInputStream("somefile")) {
    // Read data etc.
} catch (IOException ex) {
    System.err.println("IO Error processing 'somefile': " + ex.getMessage());
    return;
}

Если вы хотите различать ошибки ввода-вывода при открытии и чтении, вы можете использовать вложенный try / catch. Если вы хотите улучшить диагностику открытых сбоев, вы можете выполнить проверки exists , isFile и canRead в обработчике.