Проверьте, существует ли файл перед вызовом openFileInput - PullRequest
21 голосов
/ 15 января 2012

Для чтения файла в Android из личного хранилища вашего приложения вы используете функцию openFileInput().

У меня вопрос, есть ли способ проверить, существует ли этот файл перед вызовом этой функции? Функция может выдать FileNotFoundException, но я чувствую, что вызываю это, а затем что-то делать на основе try - catch - плохая практика.

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

Ответы [ 3 ]

46 голосов
/ 15 января 2012
public boolean fileExists(Context context, String filename) {    
    File file = context.getFileStreamPath(filename);
    if(file == null || !file.exists()) {
        return false;
    }
    return true;
}

EDIT:

Кроме того, здесь есть еще один способ для файлов во внешнем хранилище.

String fileUrl = "/appname/data.xml";
String file = android.os.Environment.getExternalStorageDirectory().getPath() + fileUrl;
File f = new File(file);

if(f.exists())
return;
30 голосов
/ 15 января 2012

Функция может через исключение FileNotFoundException, но я чувствую, что это нужно вызывать, а затем делать что-то на основе попытки перехвата - плохая практика.

Я не согласен. ИМО, это проверка, существует ли файл перед открытием, что является плохой практикой. Сравните эти две версии кода:

File f = new File("someFile");
InputStream is;

Версия # 1

if (f.exists()) {
    is = new FileInputStream(f);
    ...
} else {
    System.err.println("Doesn't exist");
}

Версия # 2

try {
    is = new FileInputStream(f);
    ...
} catch (FileNotFoundException ex) {
    System.err.println("Doesn't exist");
}

Существует ряд проблем с первой версией:

  • Версия # 1 делает дополнительный системный вызов при вызове f.exists(). Это делает первую версию медленнее в среднем, если только не существует высокой вероятности того, что файл не будет существовать.

  • Версия # 1 имеет состояние гонки. Если какой-то внешний процесс удалит файл примерно в одно и то же время, вы можете получить file.exists(), возвращающий true, а затем конструктор FileInputStream, выдавший FileNotFoundException. Это такое состояние гонки, которое можно использовать для нарушения безопасности, если рассматриваемый файл критичен к безопасности. (На самом деле, есть и второе условие гонки, когда файл создается, и file.exists() возвращает false, когда последующая попытка открыть его будет успешной. Но это условие гонки, вероятно, безвредно.)

Еще одна проблема заключается в том, что FileInputStream объявлен как выбрасывающий IOException. Тестирование, чтобы увидеть, существует ли файл, имеет дело только с одним из возможных режимов отказа. В любом случае ваш код должен будет поймать и обработать другие IOException.


@ Комментарии прокомментированы:

Исключения должны быть для случаев, когда что-то действительно идет не так, что вы не можете контролировать. В этом случае у меня есть полный контроль над ним.

На самом деле, вы не имеете полного контроля над ним. Конечно, не в общем случае. Даже в вашем конкретном случае условия гонки все еще возможны в теории.

Но настоящая проблема с этим типом мышления заключается в том, что вы в конечном итоге перепрыгиваете через обручи, чтобы избежать исключений в ситуациях, когда обработка исключений / исключений является лучшим решением. Это делает код более сложным, менее читаемым, потенциально более медленным и / или более хрупким.

Нормальная догма выглядит так:

«Исключения следует использовать только в исключительных ситуациях» .

Это не то же самое, что сказать, что вы сказали. Слово «исключительный» на самом деле просто означает «не нормально». Это имеет гораздо более широкое значение, чем «что-то идет не так, что вы не можете контролировать».

Я склонен расширять догму следующим образом:

  • Исключения не следует использовать для нормального управления потоком.

  • Исключения не следует использовать , если они окажутся слишком дорогими в среднем .

  • Исключения следует использовать , если тесты, которые вы используете, чтобы избежать их, не являются надежными.

  • Исключения следует использовать , если тесты, которые вы используете, чтобы избежать их, слишком дороги в среднем .

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

(примечание - "в среднем" и " слишком дорого" ...)

Теперь можно спорить, пока коровы не вернутся домой, о , насколько исключительным должно быть событие, но я считаю, что это действительно вопрос баланса относительной простоты подходов (в контексте) по сравнению со средними затратами на производительность (в контексте). Любое догматическое правило, которое не учитывает компромиссы и контекст, в некоторых случаях может причинить вам вред.

0 голосов
/ 29 февраля 2016

Это работает для меня.

try {
  FileInputStream fis = openFileInput(String filename);
  // ... do something
try {
    fis.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
} catch (FileNotFoundException e) { 
  e.printStackTrace();
}

, но случается, иногда это возвращает то же исключение ... работа с adb.

...