Не удается создать папку на внешнем хранилище на 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()
и т.д.