Не удается создать папку на внешнем хранилище на Android

Мой телефон разработки - Nexus 5, работает Android 4.4.2.

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

Я начал, пытаясь записать файл в папку, но обнаружил, что возникла ошибка при создании папки. Сначала я использовал mkdir(), затем перешел на mkdirs(), который также не работал.

У меня есть <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> в моем манифесте.

Вот код для создания папки:

    File folder = new File(Environment.getExternalStorageDirectory() + "/DebugData");

    String path = folder.getPath();

    if(!folder.mkdirs() || !folder.exists()){        
            Log.e(LOG_TAG, path + " failed");
        } else {
            Log.d(LOG_TAG, path + " succeeded");
        } 

Вот что я также пробовал:

    //Check SD card state
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state) || !Environment.MEDIA_MOUNTED.equals(state)) {
        Log.e(LOG_TAG, "Error: external storage is read only or unavailable");
    } else {
        Log.d(LOG_TAG, "External storage is not read only or unavailable");
    }

Это возвращает, что внешняя память не доступна только для чтения или недоступна.

Я также пробовал разные пути, такие как File folder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "Folder1");

Вот где это стало действительно запутанным.

Я пробовал разработку на разных телефонах. Во-первых, я схватил Galaxy S4 GT-i9505 running Android 4.2.2, и он сработал. Мне удалось создать папки и написать им. Это показало мне, что код работает. Также путь, возвращаемый при запуске кода на S4 и Nexus 5, был таким же.

Тогда я подумал, что это может быть версия для Android. Поэтому я схватил Nexus 4 с Android 4.4.2, и код тоже работал над ним. Создал папки и разрешил мне писать им.

Ни один из телефонов не укоренен и не является стандартным. Там нет специальных приложений или чего-либо, что я могу думать о настройках на Nexus 5, которые могут вызвать проблемы с разрешениями. Соединение установлено на Media Device (MTP).

EDIT:

Я должен добавить, что я попробовал следующее, которое также не сработало:

  • Запись файла в корневой каталог внешнего хранилища
  • Создание файла в корневом каталоге внешнего хранилища и его запись
  • Создание папки в выделенном пути и запись в нее файла
  • Создание файла в указанном пути и его записи

Я запутался в том, что вызывает это, есть ли что-нибудь еще, что я могу проверить или изменить, чтобы исправить проблему?

ИЗМЕНИТЬ 2:

Оказывается, проблема возникла из-за, я думаю, индексации.

В основном все другие устройства, на которых я тестировался, позволили мне снова подключить USB-соединение и просмотреть созданные файлы и папки.

По какой-то причине мой Nexus 5 не индексирует папки/файлы, даже если они существуют.

Я загрузил другое стороннее приложение-проводник файлов и заметил, что все папки и файлы были там.

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

Спасибо.

Ответы

Ответ 1

В связи с этим проблема индексирования с Nexus, это сработало для меня:

MediaScannerConnection.scanFile(this, new String[] { file.toString() }, null,
        new MediaScannerConnection.OnScanCompletedListener() {
            public void onScanCompleted(String path, Uri uri) {
                Log.i("ExternalStorage", "Scanned " + path + ":");
                Log.i("ExternalStorage", "-> uri=" + uri);
            }
});

Вы должны называть это сразу после создания и сохранения файла. С помощью сканера я смог видеть только что созданные файлы и каталоги, просто перегружая устройство.

В соответствии с документами:

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

Надеюсь, это поможет кому-то еще.

Ответ 2

Оказывается, проблема возникла из-за, я думаю, индексации.

В основном все другие устройства, на которых я тестировался, позволили мне снова подключить USB-соединение и просмотреть созданные файлы и папки.

По какой-то причине мой Nexus 5 не индексирует папки/файлы, даже если они существуют.

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

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

Ответ 3

Была та же проблема. Оказалось, что я тестировал Android 6 и не проверял разрешение WRITE_EXTERNAL_STORAGE для выполнения.

Ответ 4

Во-первых, новый File() просто создает объект для подключения к файлу.
вы хотите использовать этот файл, файл существует или createNewFile().
Если вы хотите использовать этот файл для создания каталога, проверьте, что файл существует, isDirectory() после этого mkDir().
Во-вторых, проверьте Environment.getExternalStorageDirectory на переменный путь.
Вы можете использовать DDMS или ADB для работы.
Кроме того, я думаю, вы добавляете разрешение на чтение внешнего хранилища для чего-то.

Ответ 5

Если вы используете Android-устройство с api >= 23, вам нужно запросить разрешение у пользователя перед вызовом функции mkdir(). Мой предыдущий ответ с примером кода можно найти fooobar.com/questions/102085/...

Ответ 6

Для android sdk версии 23 и выше вы должны проверить, предоставил ли пользователь разрешение на внешнее хранилище.

private void createFolder() {
    if (isStoragePermissionGranted()) {
        File folder = new File(Environment.getExternalStorageDirectory()+ File.separator + "DebugData");

        if(!folder.exists()){
            folder.mkdir();
        }
    }

public  boolean isStoragePermissionGranted() {
    if (Build.VERSION.SDK_INT >= 23) {
        if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                == PackageManager.PERMISSION_GRANTED) {
            return true;
        } else {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
            return false;
        }
    }
    else { //permission is automatically granted on sdk<23 upon installation
        return true;
    }
}

Этот код работал у меня, и я надеюсь, что он сработает для вас.

Ответ 7

Как правило, я делаю это:

/**
 * Return a dedicated directory named "MyApp" at the top of external storage
 */
public static file getDataDir() {
    File sdcard = Environment.getExternalStorageDirectory();
    if( sdcard == null || !sdcard.isDirectory() ) {
        // TODO: warning popup
        Log.w(TAG, "Storage card not found " + sdcard);
        return null;
    }
    File dataDir = new File(sdcard, "MyApp");
    if( !confirmDir(dataDir) ) {
        // TODO: warning popup
        Log.e(TAG, "Unable to create " + dataDir);
        return null;
    }
    return dataDir;
}   

private static boolean confirmDir(File dir) {
    if (dir.isDirectory()) return true;  // already exists
    if (dir.exists()) return false;      // already exists, but is not a directory
    return dir.mkdirs();                 // create it
}       

Также добавьте это разрешение в свой манифест:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Если вам требуется частное хранилище (обычно под /data/ ) для вашего приложения (а не на SD-карте), просмотрите getDir(), getFilesDir(), fileList(), openFileInput(), openFileOutput() и т.д.

Существуют также вспомогательные функции для получения частных каталогов в SD-карте для API 8 и выше: getExternalFilesDir(), getExternalCacheDir() и т.д.