Как я могу получить путь к внешней SD-карте для Android 4.0+?
Samsung Galaxy S3 имеет внешний слот для SD-карты, который крепится к /mnt/extSdCard
,
Мой вопрос: как пройти этот путь чем-то вроде Environment.getExternalStorageDirectory()
? Это вернется mnt/sdcard
, и я не могу найти API для внешней SD-карты. (Или съемный USB-накопитель на некоторых планшетах)
Спасибо!
27 ответов
У меня есть вариант решения, которое я нашел здесь
public static HashSet<String> getExternalMounts() {
final HashSet<String> out = new HashSet<String>();
String reg = "(?i).*vold.*(vfat|ntfs|exfat|fat32|ext3|ext4).*rw.*";
String s = "";
try {
final Process process = new ProcessBuilder().command("mount")
.redirectErrorStream(true).start();
process.waitFor();
final InputStream is = process.getInputStream();
final byte[] buffer = new byte[1024];
while (is.read(buffer) != -1) {
s = s + new String(buffer);
}
is.close();
} catch (final Exception e) {
e.printStackTrace();
}
// parse output
final String[] lines = s.split("\n");
for (String line : lines) {
if (!line.toLowerCase(Locale.US).contains("asec")) {
if (line.matches(reg)) {
String[] parts = line.split(" ");
for (String part : parts) {
if (part.startsWith("/"))
if (!part.toLowerCase(Locale.US).contains("vold"))
out.add(part);
}
}
}
}
return out;
}
Оригинальный метод был проверен и работал с
- Huawei X3 (сток)
- Galaxy S2 (сток)
- Galaxy S3 (сток)
Я не уверен, на какой версии Android они были, когда они тестировались.
Я проверил мою модифицированную версию с
- Moto Xoom 4.1.2 (сток)
- Galaxy Nexus (cyanogenmod 10) с помощью кабеля OTG
- HTC Incredible (cyanogenmod 7.2) это вернул как внутренний, так и внешний. Это устройство является своего рода странным в том смысле, что его внутреннее устройство в основном не используется, поскольку вместо него getExternalStorage() возвращает путь к sdcard.
и некоторые устройства хранения данных, которые используют SDCard в качестве основного хранилища
- HTC G1 (cyanogenmod 6.1)
- HTC G1 (сток)
- HTC Vision / G2 (сток)
За исключением Невероятного все эти устройства возвращали только свои сменные хранилища. Вероятно, есть некоторые дополнительные проверки, которые я должен сделать, но это, по крайней мере, немного лучше, чем любое решение, которое я нашел до сих пор.
Я нашел более надежный способ получить пути ко всем SD-картам в системе. Это работает на всех версиях Android и возвращает пути ко всем хранилищам (включая эмулированные).
Работает корректно на всех моих устройствах.
PS: на основе исходного кода класса Environment.
private static final Pattern DIR_SEPORATOR = Pattern.compile("/");
/**
* Raturns all available SD-Cards in the system (include emulated)
*
* Warning: Hack! Based on Android source code of version 4.3 (API 18)
* Because there is no standart way to get it.
* TODO: Test on future Android versions 4.4+
*
* @return paths to all available SD-Cards in the system (include emulated)
*/
public static String[] getStorageDirectories()
{
// Final set of paths
final Set<String> rv = new HashSet<String>();
// Primary physical SD-CARD (not emulated)
final String rawExternalStorage = System.getenv("EXTERNAL_STORAGE");
// All Secondary SD-CARDs (all exclude primary) separated by ":"
final String rawSecondaryStoragesStr = System.getenv("SECONDARY_STORAGE");
// Primary emulated SD-CARD
final String rawEmulatedStorageTarget = System.getenv("EMULATED_STORAGE_TARGET");
if(TextUtils.isEmpty(rawEmulatedStorageTarget))
{
// Device has physical external storage; use plain paths.
if(TextUtils.isEmpty(rawExternalStorage))
{
// EXTERNAL_STORAGE undefined; falling back to default.
rv.add("/storage/sdcard0");
}
else
{
rv.add(rawExternalStorage);
}
}
else
{
// Device has emulated storage; external storage paths should have
// userId burned into them.
final String rawUserId;
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)
{
rawUserId = "";
}
else
{
final String path = Environment.getExternalStorageDirectory().getAbsolutePath();
final String[] folders = DIR_SEPORATOR.split(path);
final String lastFolder = folders[folders.length - 1];
boolean isDigit = false;
try
{
Integer.valueOf(lastFolder);
isDigit = true;
}
catch(NumberFormatException ignored)
{
}
rawUserId = isDigit ? lastFolder : "";
}
// /storage/emulated/0[1,2,...]
if(TextUtils.isEmpty(rawUserId))
{
rv.add(rawEmulatedStorageTarget);
}
else
{
rv.add(rawEmulatedStorageTarget + File.separator + rawUserId);
}
}
// Add all secondary storages
if(!TextUtils.isEmpty(rawSecondaryStoragesStr))
{
// All Secondary SD-CARDs splited into array
final String[] rawSecondaryStorages = rawSecondaryStoragesStr.split(File.pathSeparator);
Collections.addAll(rv, rawSecondaryStorages);
}
return rv.toArray(new String[rv.size()]);
}
Я думаю, чтобы использовать внешнюю SDCard вам нужно использовать это:
new File("/mnt/external_sd/")
ИЛИ ЖЕ
new File("/mnt/extSdCard/")
в твоем случае...
вместо Environment.getExternalStorageDirectory()
Работает для меня. Вы должны сначала проверить, что находится в каталоге mnt, и работать оттуда..
Вы должны использовать метод выбора, чтобы выбрать, какую SDCard использовать:
File storageDir = new File("/mnt/");
if(storageDir.isDirectory()){
String[] dirList = storageDir.list();
//TODO some type of selecton method?
}
Я использовал решение Дмитрия Лозенко, пока не проверил Asus Zenfone2, Marshmallow 6.0.1, и решение не работает. Решение не удалось получить EMULATED_STORAGE_TARGET, особенно для пути microSD, например: / storage / F99C-10F4 /. Я отредактировал код, чтобы получить эмулированные корневые пути непосредственно из эмулированных путей приложений с помощью context.getExternalFilesDirs(null);
и добавьте более известные физические пути, специфичные для модели телефона.
Чтобы облегчить нашу жизнь, я сделал здесь библиотеку. Вы можете использовать его через систему сборки gradle, maven, sbt и leiningen.
Если вам нравится старомодный способ, вы также можете скопировать и вставить файл прямо отсюда, но вы не узнаете, будет ли обновление в будущем, не проверив его вручную.
Если у вас есть какие-либо вопросы или предложения, пожалуйста, дайте мне знать
Чтобы извлечь все внешние хранилища (будь то карты SD или внутренние несъемные хранилища), вы можете использовать следующий код:
final String state = Environment.getExternalStorageState();
if ( Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state) ) { // we can read the External Storage...
//Retrieve the primary External Storage:
final File primaryExternalStorage = Environment.getExternalStorageDirectory();
//Retrieve the External Storages root directory:
final String externalStorageRootDir;
if ( (externalStorageRootDir = primaryExternalStorage.getParent()) == null ) { // no parent...
Log.d(TAG, "External Storage: " + primaryExternalStorage + "\n");
}
else {
final File externalStorageRoot = new File( externalStorageRootDir );
final File[] files = externalStorageRoot.listFiles();
for ( final File file : files ) {
if ( file.isDirectory() && file.canRead() && (file.listFiles().length > 0) ) { // it is a real directory (not a USB drive)...
Log.d(TAG, "External Storage: " + file.getAbsolutePath() + "\n");
}
}
}
}
В качестве альтернативы вы можете использовать System.getenv("EXTERNAL_STORAGE") для получения первичного каталога внешнего хранилища (например, "/ storage / sdcard0") и System.getenv("SECONDARY_STORAGE") для получения списка всех вторичных каталогов (например, " / storage / extSdCard: / storage / UsbDriveA: / storage / UsbDriveB "). Помните, что и в этом случае вам может потребоваться отфильтровать список вторичных каталогов, чтобы исключить USB-накопители.
В любом случае, обратите внимание, что использование жестко закодированных путей - это всегда плохой подход (особенно, когда каждый производитель может изменить его по своему усмотрению).
Хорошие новости! В KitKat теперь есть открытый API для взаимодействия с этими вторичными общими устройствами хранения.
Новый Context.getExternalFilesDirs()
а также Context.getExternalCacheDirs()
методы могут возвращать несколько путей, включая как первичные, так и вторичные устройства. Затем вы можете перебрать их и проверить Environment.getStorageState()
а также File.getFreeSpace()
определить лучшее место для хранения ваших файлов. Эти методы также доступны на ContextCompat
в библиотеке поддержки-v4.
Также обратите внимание, что если вы заинтересованы только в использовании каталогов, возвращаемых Context
вам больше не нужно READ_
или же WRITE_EXTERNAL_STORAGE
разрешения. В дальнейшем у вас всегда будет доступ на чтение / запись к этим каталогам без дополнительных разрешений.
Приложения также могут продолжать работать на старых устройствах, отменив запрос на разрешение, например, так:
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />
Я сделал следующее, чтобы получить доступ ко всем внешним SD-карт.
С:
File primaryExtSd=Environment.getExternalStorageDirectory();
Вы получаете путь к первичной внешней SD. Затем с помощью:
File parentDir=new File(primaryExtSd.getParent());
Вы получаете родительский каталог первичного внешнего хранилища, а также родитель всех внешних внешних дисков. Теперь вы можете перечислить все хранилище и выбрать тот, который вы хотите.
Надеюсь, это полезно.
Вот как я получаю список путей SD-карты (исключая основное внешнее хранилище):
/**
* returns a list of all available sd cards paths, or null if not found.
*
* @param includePrimaryExternalStorage set to true if you wish to also include the path of the primary external storage
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static List<String> getSdCardPaths(final Context context,final boolean includePrimaryExternalStorage)
{
final File[] externalCacheDirs=ContextCompat.getExternalCacheDirs(context);
if(externalCacheDirs==null||externalCacheDirs.length==0)
return null;
if(externalCacheDirs.length==1)
{
if(externalCacheDirs[0]==null)
return null;
final String storageState=EnvironmentCompat.getStorageState(externalCacheDirs[0]);
if(!Environment.MEDIA_MOUNTED.equals(storageState))
return null;
if(!includePrimaryExternalStorage&&VERSION.SDK_INT>=VERSION_CODES.HONEYCOMB&&Environment.isExternalStorageEmulated())
return null;
}
final List<String> result=new ArrayList<>();
if(includePrimaryExternalStorage||externalCacheDirs.length==1)
result.add(getRootOfInnerSdCardFolder(externalCacheDirs[0]));
for(int i=1;i<externalCacheDirs.length;++i)
{
final File file=externalCacheDirs[i];
if(file==null)
continue;
final String storageState=EnvironmentCompat.getStorageState(file);
if(Environment.MEDIA_MOUNTED.equals(storageState))
result.add(getRootOfInnerSdCardFolder(externalCacheDirs[i]));
}
if(result.isEmpty())
return null;
return result;
}
/** Given any file/folder inside an sd card, this will return the path of the sd card */
private static String getRootOfInnerSdCardFolder(File file)
{
if(file==null)
return null;
final long totalSpace=file.getTotalSpace();
while(true)
{
final File parentFile=file.getParentFile();
if(parentFile==null||parentFile.getTotalSpace()!=totalSpace)
return file.getAbsolutePath();
file=parentFile;
}
}
Спасибо за подсказки, предоставленные вами, ребята, особенно @SmartLemon, я нашел решение. Если кому-то еще это понадобится, я выложу свое окончательное решение здесь (чтобы найти первую из перечисленных внешних SD-карт):
public File getExternalSDCardDirectory()
{
File innerDir = Environment.getExternalStorageDirectory();
File rootDir = innerDir.getParentFile();
File firstExtSdCard = innerDir ;
File[] files = rootDir.listFiles();
for (File file : files) {
if (file.compareTo(innerDir) != 0) {
firstExtSdCard = file;
break;
}
}
//Log.i("2", firstExtSdCard.getAbsolutePath().toString());
return firstExtSdCard;
}
Если там нет внешней SD-карты, она возвращает встроенную память. Я буду использовать его, если SDCard не существует, возможно, вам придется изменить его.
Обратитесь к моему коду, надеюсь, полезно для вас:
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec("mount");
InputStream is = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
String line;
String mount = new String();
BufferedReader br = new BufferedReader(isr);
while ((line = br.readLine()) != null) {
if (line.contains("secure")) continue;
if (line.contains("asec")) continue;
if (line.contains("fat")) {//TF card
String columns[] = line.split(" ");
if (columns != null && columns.length > 1) {
mount = mount.concat("*" + columns[1] + "\n");
}
} else if (line.contains("fuse")) {//internal storage
String columns[] = line.split(" ");
if (columns != null && columns.length > 1) {
mount = mount.concat(columns[1] + "\n");
}
}
}
txtView.setText(mount);
Это решение (собранное из других ответов на этот вопрос) обрабатывает тот факт (как упомянуто @ono), что System.getenv("SECONDARY_STORAGE")
бесполезен с Зефиром.
Протестировано и работает над:
- Samsung Galaxy Tab 2 (Android 4.1.1 - сток)
- Samsung Galaxy Note 8.0 (Android 4.2.2 - сток)
- Samsung Galaxy S4 (Android 4.4 - сток)
- Samsung Galaxy S4 (Android 5.1.1 - Cyanogenmod)
Samsung Galaxy Tab A (Android 6.0.1 - сток)
/** * Returns all available external SD-Card roots in the system. * * @return paths to all available external SD-Card roots in the system. */ public static String[] getStorageDirectories() { String [] storageDirectories; String rawSecondaryStoragesStr = System.getenv("SECONDARY_STORAGE"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { List<String> results = new ArrayList<String>(); File[] externalDirs = applicationContext.getExternalFilesDirs(null); for (File file : externalDirs) { String path = file.getPath().split("/Android")[0]; if((Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Environment.isExternalStorageRemovable(file)) || rawSecondaryStoragesStr != null && rawSecondaryStoragesStr.contains(path)){ results.add(path); } } storageDirectories = results.toArray(new String[0]); }else{ final Set<String> rv = new HashSet<String>(); if (!TextUtils.isEmpty(rawSecondaryStoragesStr)) { final String[] rawSecondaryStorages = rawSecondaryStoragesStr.split(File.pathSeparator); Collections.addAll(rv, rawSecondaryStorages); } storageDirectories = rv.toArray(new String[rv.size()]); } return storageDirectories; }
На самом деле в некоторых устройствах внешнее имя SDCard по умолчанию отображается как extSdCard
а для других это sdcard1
,
Этот фрагмент кода помогает определить точный путь и получить путь к внешнему устройству.
String sdpath,sd1path,usbdiskpath,sd0path;
if(new File("/storage/extSdCard/").exists())
{
sdpath="/storage/extSdCard/";
Log.i("Sd Cardext Path",sdpath);
}
if(new File("/storage/sdcard1/").exists())
{
sd1path="/storage/sdcard1/";
Log.i("Sd Card1 Path",sd1path);
}
if(new File("/storage/usbcard1/").exists())
{
usbdiskpath="/storage/usbcard1/";
Log.i("USB Path",usbdiskpath);
}
if(new File("/storage/sdcard0/").exists())
{
sd0path="/storage/sdcard0/";
Log.i("Sd Card0 Path",sd0path);
}
Да. Разные производители используют разные названия SD-карт, как в Samsung Tab 3, его extsd, а другие устройства Samsung используют SDCard, как и другие производители используют разные имена.
У меня было такое же требование, как и у вас. поэтому я создал для вас пример из моего проекта. Перейдите по этой ссылке. Пример выбора каталога Android, в котором используется библиотека androi-dirchooser. В этом примере обнаруживается SD-карта и выводится список всех вложенных папок, а также обнаруживается, имеет ли устройство более одной SD-карты.
Часть кода выглядит следующим образом. Для полного примера перейдите по ссылке Android Directory Chooser
/**
* Returns the path to internal storage ex:- /storage/emulated/0
*
* @return
*/
private String getInternalDirectoryPath() {
return Environment.getExternalStorageDirectory().getAbsolutePath();
}
/**
* Returns the SDcard storage path for samsung ex:- /storage/extSdCard
*
* @return
*/
private String getSDcardDirectoryPath() {
return System.getenv("SECONDARY_STORAGE");
}
mSdcardLayout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
String sdCardPath;
/***
* Null check because user may click on already selected buton before selecting the folder
* And mSelectedDir may contain some wrong path like when user confirm dialog and swith back again
*/
if (mSelectedDir != null && !mSelectedDir.getAbsolutePath().contains(System.getenv("SECONDARY_STORAGE"))) {
mCurrentInternalPath = mSelectedDir.getAbsolutePath();
} else {
mCurrentInternalPath = getInternalDirectoryPath();
}
if (mCurrentSDcardPath != null) {
sdCardPath = mCurrentSDcardPath;
} else {
sdCardPath = getSDcardDirectoryPath();
}
//When there is only one SDcard
if (sdCardPath != null) {
if (!sdCardPath.contains(":")) {
updateButtonColor(STORAGE_EXTERNAL);
File dir = new File(sdCardPath);
changeDirectory(dir);
} else if (sdCardPath.contains(":")) {
//Multiple Sdcards show root folder and remove the Internal storage from that.
updateButtonColor(STORAGE_EXTERNAL);
File dir = new File("/storage");
changeDirectory(dir);
}
} else {
//In some unknown scenario at least we can list the root folder
updateButtonColor(STORAGE_EXTERNAL);
File dir = new File("/storage");
changeDirectory(dir);
}
}
});
На некоторых устройствах (например, samsung galaxy sII) внутренняя карта памяти может быть в vfat. В этом случае используйте ссылку на последний код, мы получаем путь к внутренней карте памяти (/mnt/sdcad), но без внешней карты. Код ниже, чтобы решить эту проблему.
static String getExternalStorage(){
String exts = Environment.getExternalStorageDirectory().getPath();
try {
FileReader fr = new FileReader(new File("/proc/mounts"));
BufferedReader br = new BufferedReader(fr);
String sdCard=null;
String line;
while((line = br.readLine())!=null){
if(line.contains("secure") || line.contains("asec")) continue;
if(line.contains("fat")){
String[] pars = line.split("\\s");
if(pars.length<2) continue;
if(pars[1].equals(exts)) continue;
sdCard =pars[1];
break;
}
}
fr.close();
br.close();
return sdCard;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
System.getenv("SECONDARY_STORAGE")
возвращает ноль для Зефира. Это еще один способ найти все внешние каталоги. Вы можете проверить, является ли это съемным, который определяет, является ли внутренний / внешний
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
File[] externalCacheDirs = context.getExternalCacheDirs();
for (File file : externalCacheDirs) {
if (Environment.isExternalStorageRemovable(file)) {
// It's a removable storage
}
}
}
File[] files = null;
File file = new File("/storage");// /storage/emulated
if (file.exists()) {
files = file.listFiles();
}
if (null != files)
for (int j = 0; j < files.length; j++) {
Log.e(TAG, "" + files[j]);
Log.e(TAG, "//--//--// " + files[j].exists());
if (files[j].toString().replaceAll("_", "")
.toLowerCase().contains("extsdcard")) {
external_path = files[j].toString();
break;
} else if (files[j].toString().replaceAll("_", "")
.toLowerCase()
.contains("sdcard".concat(Integer.toString(j)))) {
// external_path = files[j].toString();
}
Log.e(TAG, "--///--///-- " + external_path);
}
Я попробовал решения, предоставленные Дмитрием Лозенко и Gnathonic, на моем Samsung Galaxy Tab S2 (модель: T819Y), но ни одно из них не помогло мне найти путь к внешнему каталогу SD-карты. mount
Выполнение команды содержало требуемый путь к внешнему каталогу SD-карты (т. е. /Storage/A5F9-15F4), но оно не соответствовало регулярному выражению, поэтому оно не было возвращено. Я не понимаю, как работает механизм именования каталогов от Samsung. Почему они отклоняются от стандартов (например, extsdcard) и придумывают нечто действительно подозрительное, как в моем случае (например, / Storage / A5F9-15F4). Есть что-то, что я пропускаю В любом случае, следующие изменения в регулярном выражении решения Gnathonic помогли мне получить действительный каталог sdcard:
final HashSet<String> out = new HashSet<String>();
String reg = "(?i).*(vold|media_rw).*(sdcard|vfat|ntfs|exfat|fat32|ext3|ext4).*rw.*";
String s = "";
try {
final Process process = new ProcessBuilder().command("mount")
.redirectErrorStream(true).start();
process.waitFor();
final InputStream is = process.getInputStream();
final byte[] buffer = new byte[1024];
while (is.read(buffer) != -1) {
s = s + new String(buffer);
}
is.close();
} catch (final Exception e) {
e.printStackTrace();
}
// parse output
final String[] lines = s.split("\n");
for (String line : lines) {
if (!line.toLowerCase(Locale.US).contains("asec")) {
if (line.matches(reg)) {
String[] parts = line.split(" ");
for (String part : parts) {
if (part.startsWith("/"))
if (!part.toLowerCase(Locale.US).contains("vold"))
out.add(part);
}
}
}
}
return out;
Я не уверен, является ли это верным решением и даст ли оно результаты для других планшетов Samsung, но это решило мою проблему на данный момент. Ниже приведен еще один способ получения пути к съемной SD-карте в Android (v6.0). Я проверил метод с зефиром Android, и он работает. Используемый в нем подход очень прост и, безусловно, будет работать и для других версий, но тестирование обязательно. Некоторое понимание этого будет полезно:
public static String getSDCardDirPathForAndroidMarshmallow() {
File rootDir = null;
try {
// Getting external storage directory file
File innerDir = Environment.getExternalStorageDirectory();
// Temporarily saving retrieved external storage directory as root
// directory
rootDir = innerDir;
// Splitting path for external storage directory to get its root
// directory
String externalStorageDirPath = innerDir.getAbsolutePath();
if (externalStorageDirPath != null
&& externalStorageDirPath.length() > 1
&& externalStorageDirPath.startsWith("/")) {
externalStorageDirPath = externalStorageDirPath.substring(1,
externalStorageDirPath.length());
}
if (externalStorageDirPath != null
&& externalStorageDirPath.endsWith("/")) {
externalStorageDirPath = externalStorageDirPath.substring(0,
externalStorageDirPath.length() - 1);
}
String[] pathElements = externalStorageDirPath.split("/");
for (int i = 0; i < pathElements.length - 1; i++) {
rootDir = rootDir.getParentFile();
}
File[] files = rootDir.listFiles();
for (File file : files) {
if (file.exists() && file.compareTo(innerDir) != 0) {
// Try-catch is implemented to prevent from any IO exception
try {
if (Environment.isExternalStorageRemovable(file)) {
return file.getAbsolutePath();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
Пожалуйста, поделитесь, если у вас есть какой-либо другой подход к решению этой проблемы. Спасибо
Вы можете использовать что-то вроде - Context.getExternalCacheDirs() или Context.getExternalFilesDirs() или Context.getObbDirs(). Они предоставляют специальные каталоги приложений на всех внешних устройствах хранения, где приложение может хранить свои файлы.
Поэтому что-то вроде этого - Context.getExternalCacheDirs()[i].getParentFile(). GetParentFile (). GetParentFile (). GetParent() может получить корневой путь внешних устройств хранения.
Я знаю, что эти команды предназначены для другой цели, но другие ответы не работали для меня.
Эта ссылка дала мне хорошие советы - https://possiblemobile.com/2014/03/android-external-storage/
String path = Environment.getExternalStorageDirectory()
+ File.separator + Environment.DIRECTORY_PICTURES;
File dir = new File(path);
Это вывод всех надежных методов, работающих на всех версиях Android (надеюсь).
private static ArrayList<String> getAllStorages(Context context)
{
ArrayList<String> storagePaths = new ArrayList<>();
storagePaths.add(Environment.getExternalStorageDirectory().getAbsolutePath());
try
{
File[] externalDirs = context.getExternalFilesDirs(null);
if (externalDirs != null)
for (File file : externalDirs)
{
storagePaths.add(file.getAbsolutePath());
}
externalDirs = context.getExternalMediaDirs();
if (externalDirs != null)
for (File file : externalDirs)
{
storagePaths.add(file.getAbsolutePath());
}
}
catch (Throwable e)
{
// ignore
}
try
{
StorageManager sm=(StorageManager) context.getSystemService(context.STORAGE_SERVICE);
for (StorageVolume e:sm.getStorageVolumes())
{
String s= (String) StorageVolume.class.getMethod("getPath").invoke(e);
storagePaths.add(s);
}
}
catch (Throwable e)
{
//ignore
}
for (String key: new String[]{
"SECONDARY_STORAGE",
"EXTERNAL_STORAGE",
"EMULATED_STORAGE_TARGET"
})
{
String externalStorage = System.getenv(key);
if (externalStorage != null && !externalStorage.isEmpty())
{
String[] externalPaths = externalStorage.split(":");
for (String e:externalPaths)
{
storagePaths.add(e);
}
}
}
ArrayList<String> result=new ArrayList<>();
for (String s:storagePaths)
{
File f=new File(s);
File f2=f;
while (f2 != null)
{
if (f2.canRead())
{
f = f2;
}
f2 = f2.getParentFile();
}
try
{
f = f.getCanonicalFile();
}
catch (IOException e)
{
// ignore
}
s = f.getPath();
if (!result.contains(s))
{
result.add(s);
}
}
return result;
}
Протестировано на Android 11.
Вам следует протестировать его на каждой версии и оставить комментарий ниже, если какая-либо из них несовместима, чтобы вы могли ее улучшить.
String secStore = System.getenv("SECONDARY_STORAGE");
File externalsdpath = new File(secStore);
Это позволит получить путь к внешнему SD-хранилищу.
Для доступа к файлам на моей SD-карте в HTC One X (Android) я использую этот путь:
file:///storage/sdcard0/folder/filename.jpg
Обратите внимание на тройку "/"!
Я уверен, что этот код наверняка решит ваши проблемы... Это нормально работает для меня...\
try {
File mountFile = new File("/proc/mounts");
usbFoundCount=0;
sdcardFoundCount=0;
if(mountFile.exists())
{
Scanner usbscanner = new Scanner(mountFile);
while (usbscanner.hasNext()) {
String line = usbscanner.nextLine();
if (line.startsWith("/dev/fuse /storage/usbcard1")) {
usbFoundCount=1;
Log.i("-----USB--------","USB Connected and properly mounted---/dev/fuse /storage/usbcard1" );
}
}
}
if(mountFile.exists()){
Scanner sdcardscanner = new Scanner(mountFile);
while (sdcardscanner.hasNext()) {
String line = sdcardscanner.nextLine();
if (line.startsWith("/dev/fuse /storage/sdcard1")) {
sdcardFoundCount=1;
Log.i("-----USB--------","USB Connected and properly mounted---/dev/fuse /storage/sdcard1" );
}
}
}
if(usbFoundCount==1)
{
Toast.makeText(context,"USB Connected and properly mounted", 7000).show();
Log.i("-----USB--------","USB Connected and properly mounted" );
}
else
{
Toast.makeText(context,"USB not found!!!!", 7000).show();
Log.i("-----USB--------","USB not found!!!!" );
}
if(sdcardFoundCount==1)
{
Toast.makeText(context,"SDCard Connected and properly mounted", 7000).show();
Log.i("-----SDCard--------","SDCard Connected and properly mounted" );
}
else
{
Toast.makeText(context,"SDCard not found!!!!", 7000).show();
Log.i("-----SDCard--------","SDCard not found!!!!" );
}
}catch (Exception e) {
e.printStackTrace();
}
//manifest file outside the application tag
//please give permission write this
//<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
File file = new File("/mnt");
String[] fileNameList = file.list(); //file names list inside the mnr folder
String all_names = ""; //for the log information
String foundedFullNameOfExtCard = ""; // full name of ext card will come here
boolean isExtCardFounded = false;
for (String name : fileNameList) {
if (!isExtCardFounded) {
isExtCardFounded = name.contains("ext");
foundedFullNameOfExtCard = name;
}
all_names += name + "\n"; // for log
}
Log.d("dialog", all_names + foundedFullNameOfExtCard);
Это не правда. /mnt/sdcard/external_sd может существовать, даже если SD-карта не установлена. ваше приложение будет зависать при попытке записи в / mnt / sdcard / external_sd, когда оно не смонтировано.
Вы должны проверить, установлена ли SD-карта сначала, используя:
boolean isSDPresent = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
Следующие шаги работали для меня. Вам просто нужно написать следующие строки:
String sdf = new String(Environment.getExternalStorageDirectory().getName());
String sddir = new String(Environment.getExternalStorageDirectory().getPath().replace(sdf,""));
В первой строке будет указано имя каталога sd, и вам просто нужно использовать его в методе замены для второй строки. Вторая строка будет содержать путь для внутреннего и сменного SD (в моем случае /storage/). Мне просто нужен этот путь для моего приложения, но вы можете пойти дальше, если вам это нужно.
На Galaxy S3 Android 4.3 я использую путь ./storage/extSdCard/Card/, и он делает свою работу. Надеюсь, поможет,