Приложение для Android создает каталог для большинства приложений, но на многих выдает ошибку, не позволяющую создать каталог на SD-карте.

Мое приложение создает имя каталога на SD-карте телефона и хранит в нем кучу изображений. Код работает нормально для большинства пользователей, но некоторые сообщают об ошибках при сохранении файлов.

Вот код, который создает каталог: R.string.dir имеет значение «/appname/»

dir = Environment.getExternalStorageDirectory() + ((String) getResources().getText(R.string.dir));

if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){
    File fDir = new File(dir);
    fDir.mkdirs();
}
else{
    showToast(false,"This Application needs a mounted external storage (sdcard).");
    finish();
}

Таким образом, в этот момент каталог должен быть создан (в конечном итоге он будет /mnt/sdcard/appname), иначе приложение завершит работу.

Однако при попытке сохранить файл некоторые пользователи сообщают об этом исключении:

Msg: java.io.FileNotFoundException: /mnt/sdcard/appname/file.jpg (Нет такого файла или каталога)

Код, который делает сохранение:

File file = new File("/mnt/sdcard/appname/file.jpg");
FileOutputStream fos = null;
try {
    fos = new FileOutputStream( file );
    b.compress(Bitmap.CompressFormat.JPEG, 100, fos );
}
catch( Exception e ) {

Какие-либо предложения? Может ли быть так, что mkdirs() возвращает false (хорошо, если каталог уже создан, но тогда я смогу записать туда файл)? Что может быть еще одной причиной для возврата false, если SD-карта смонтирована? Как я могу справиться с этим лучше?

Да, мы используем уникальные имена файлов (добавляя System.currentTimeMillis() к имени файла). Также поток закрывается в конце

        finally
        {

        if(fos != null) {

        try {

        fos.close();

        }
        catch(Exception ex){

        ex.printStackTrace();

        }

        }

person jetson    schedule 12.07.2011    source источник
comment
Пожалуйста, отформатируйте исходный код соответствующим образом при вставке кода. Добро пожаловать в СО.   -  person citizen conn    schedule 13.07.2011
comment
Вы проверили, потенциально ли карта смонтирована только для чтения?   -  person thegrinner    schedule 13.07.2011
comment
Citizen conn: это мой первый пост, не уверен, что мой код уже был отредактирован или я должен как-то его отредактировать, чтобы что-то исправить. Есть ли какая-то страница с информацией о том, как мы должны форматировать код перед публикацией, которую я пропустил?   -  person jetson    schedule 13.07.2011


Ответы (2)


Вы предполагаете (во втором примере кода), что пути SD-карты на всех устройствах /mnt/sdcard/. Это неправильное предположение. вам следует вызвать Environment.getExternalStorageDirectory, чтобы получить правильный путь.

Кроме того, возможно, каталог там, но не файл, добавьте следующий код перед открытием выходного потока:

if (!file.exists()) {
    file.createNewFile();
}
person MByD    schedule 12.07.2011
comment
вы пропустили dir = Environment.getExternalStorageDirectory выше в коде? - person jetson; 13.07.2011
comment
@jetson Вы также используете вызов Environment.getExternalStorageDirectory в коде создания файла? - person Shane Wealti; 13.07.2011
comment
Нет, это в первом образце. посмотрите пример файла сохранения: File file = new File("/mnt/sdcard/appname/file.jpg"); - person MByD; 13.07.2011
comment
Возможно, это бесполезно? stackoverflow.com/questions/6311852 / глупая вещь, как мне сделать возврат каретки, не публикуя его, то есть вот цитата. Вы ничего не можете с этим поделать на законных основаниях - OEM-производитель лжет вам. Так что, если мы не можем получить «истинное» местоположение, мало ли что можно сделать правильно? - person jetson; 13.07.2011
comment
Может быть. по-прежнему будьте последовательны, если вы получаете путь одним способом в первом методе, получите его таким же образом во втором... Потому что это может быть ошибка OEM, но также может быть и ваша... - person MByD; 13.07.2011
comment
Ну, я могу проверить, есть ли каталог, проблема в том, что я могу сделать, если его нет. Потому что в этот момент я не знаю, где смонтирована SD-карта, поэтому я не могу создать ПРАВИЛЬНУЮ директорию. Есть идеи? - person jetson; 13.07.2011

Подводя итог тому, в каком направлении идут другие посты, приведем некоторые потенциальные проблемы.

  1. Имена не совпадают в первом и втором методе (или могут быть, не знаю)
  2. Поскольку вы жестко кодируете имя, файл может уже существовать
  3. Вы не закрываете поток
  4. Вы сказали, что строка в ресурсе была установлена ​​​​на /appname/, надеюсь, вы имеете в виду имя вашего приложения, многие люди могут использовать буквальное имя приложения и file.jpg для хранения вещей, поскольку это появляется во многих учебниках и т. д.

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

    String sdCard = Environment.getExternalStorageDirectory() + ((String) getResources().getText(R.string.dir));
    File file     = new File(sdCard + "/appname/file.jpg"); // DO YOU WANT YOUR APP NAME OR JUST APPNAME ??? 

    if (file.exists()) // if the jpg already exists --- problems 
       file.delete(); 

    FileOutputStream fos = null;
    try {
        fos = new FileOutputStream(file.getPath());
        b.compress(Bitmap.CompressFormat.JPEG, 100, fos );
        fos.close(); 
    }
    catch( Exception e ) { ... }

Помимо этого могут быть и другие потенциальные проблемы. Если у пользователя есть устройство, подключенное к USB и настроенное как жесткий диск, SD-карта может быть недоступна, SD-карта может быть доступна только для чтения, у пользователя может не быть SD-карты (которую вы проверяете, поэтому вычеркните ее)

person Idistic    schedule 12.07.2011
comment
есть дополнительный код для захвата фактического «имени приложения» и т. д., который не был включен во вставленный код... кажется, что основная проблема заключается в различиях между телефонами Android/OEMS в соответствии с stackoverflow.com/questions/6311852/ поэтому, похоже, вам нужно проявить творческий подход, чтобы получить вокруг него для разных телефонов... - person jetson; 13.07.2011
comment
Я не думаю, что это ваша проблема, хотя @jetson Описанная там проблема заключается в том, что он возвращает внутренний путь хранения вместо внешнего пути хранения, хотя это точно стоит отметить. Я видел ошибку отказа в доступе, когда файл присутствует, и вы пытаетесь перезаписать его, используете ли вы уникальные имена для файлов. Также в полном коде вы закрываете поток? - person Idistic; 13.07.2011
comment
Я также хотел бы спросить этих пользователей, испытывают ли они это при подключении через USB-кабель. - person Idistic; 13.07.2011
comment
Да, мы используем уникальные имена файлов (добавляя System.currentTimeMillis() к имени файла). Также поток закрывается в конце finally { if(fos != null) { try { fos.close(); } catch(Exception ex){ ex.printStackTrace(); } } - person jetson; 13.07.2011