find一个外部SD卡位置
有没有一种通用的方式来find外部SD卡的位置?
请不要与外部存储混淆。 Environment.getExternalStorageState()
返回内部SD挂载点的path,如“/ mnt / sdcard”。 但问题是关于外部可持续发展。 如何得到像“/ mnt / sdcard / external_sd”的path(它可能因设备而异)?
我想我会通过文件系统名称来过滤mount
命令。 但我不确定这个方法是否足够强大。
Environment.getExternalStorageState()
返回内部SD挂载点的path,如“/ mnt / sdcard”
不, Environment.getExternalStorageDirectory()
是指任何设备制造商认为是“外部存储”。 在某些设备上,这是可移动媒体,如SD卡。 在某些设备上,这是设备上闪存的一部分。 在这里,“外部存储”是指“安装在主机上时通过USB大容量存储模式访问的东西”,至less对于Android 1.x和2.x.
但问题是关于外部可持续发展。 如何得到像“/ mnt / sdcard / external_sd”的path(它可能因设备而异)?
除了外部存储,Android没有“外部SD”的概念,如上所述。
如果设备制造商select将外部存储设备设置为板载闪存并且还具有SD卡,则需要联系制造商以确定您是否可以使用SD卡(不保证)以及规则是什么使用它,比如使用什么path。
UPDATE
最近两件值得注意的事情:
首先,在Android 4.4+上,除了可能由getExternalFilesDirs()
和getExternalCacheDirs()
返回的介质上的任何位置外,您没有可移动介质(例如“外部SD”)的写入权限。 看戴夫·史密斯对此的优秀分析 ,特别是如果你想要低级细节。
其次,为了避免任何人对移动媒体访问是否是Android SDK的一部分提出质疑,下面是Dianne Hackborn的评估 :
…请记住:除了Android 4.4之外,官方Android平台根本不支持SD卡,除了两种特殊情况:外部存储为SD卡的老式存储布局(目前仍支持SD卡) ,以及一个添加到Android 3.0的小function,它将扫描额外的SD卡并将其添加到媒体提供商,并为应用程序提供对其文件的只读访问权限(目前在该平台中仍受支持)。
Android 4.4是该平台的第一个版本,实际上允许应用程序使用SD卡进行存储。 在此之前的任何访问都是通过私有的,不受支持的API来实现的。 我们现在在这个平台上有一个相当丰富的API,允许应用程序以更好的方式以支持的方式使用SD卡:他们可以免费使用他们的应用程序特定的存储区域,而不需要任何在应用程序中的权限,只要他们通过文件select器,可以访问SD卡上的任何其他文件,而不需要任何特殊的权限。
基于在这里find的一些答案,我想出了以下解决scheme。
码:
public class ExternalStorage { public static final String SD_CARD = "sdCard"; public static final String EXTERNAL_SD_CARD = "externalSdCard"; /** * @return True if the external storage is available. False otherwise. */ public static boolean isAvailable() { String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { return true; } return false; } public static String getSdCardPath() { return Environment.getExternalStorageDirectory().getPath() + "/"; } /** * @return True if the external storage is writable. False otherwise. */ public static boolean isWritable() { String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)) { return true; } return false; } /** * @return A map of all storage locations available */ public static Map<String, File> getAllStorageLocations() { Map<String, File> map = new HashMap<String, File>(10); List<String> mMounts = new ArrayList<String>(10); List<String> mVold = new ArrayList<String>(10); mMounts.add("/mnt/sdcard"); mVold.add("/mnt/sdcard"); try { File mountFile = new File("/proc/mounts"); if(mountFile.exists()){ Scanner scanner = new Scanner(mountFile); while (scanner.hasNext()) { String line = scanner.nextLine(); if (line.startsWith("/dev/block/vold/")) { String[] lineElements = line.split(" "); String element = lineElements[1]; // don't add the default mount path // it's already in the list. if (!element.equals("/mnt/sdcard")) mMounts.add(element); } } } } catch (Exception e) { e.printStackTrace(); } try { File voldFile = new File("/system/etc/vold.fstab"); if(voldFile.exists()){ Scanner scanner = new Scanner(voldFile); while (scanner.hasNext()) { String line = scanner.nextLine(); if (line.startsWith("dev_mount")) { String[] lineElements = line.split(" "); String element = lineElements[2]; if (element.contains(":")) element = element.substring(0, element.indexOf(":")); if (!element.equals("/mnt/sdcard")) mVold.add(element); } } } } catch (Exception e) { e.printStackTrace(); } for (int i = 0; i < mMounts.size(); i++) { String mount = mMounts.get(i); if (!mVold.contains(mount)) mMounts.remove(i--); } mVold.clear(); List<String> mountHash = new ArrayList<String>(10); for(String mount : mMounts){ File root = new File(mount); if (root.exists() && root.isDirectory() && root.canWrite()) { File[] list = root.listFiles(); String hash = "["; if(list!=null){ for(File f : list){ hash += f.getName().hashCode()+":"+f.length()+", "; } } hash += "]"; if(!mountHash.contains(hash)){ String key = SD_CARD + "_" + map.size(); if (map.size() == 0) { key = SD_CARD; } else if (map.size() == 1) { key = EXTERNAL_SD_CARD; } mountHash.add(hash); map.put(key, root); } } } mMounts.clear(); if(map.isEmpty()){ map.put(SD_CARD, Environment.getExternalStorageDirectory()); } return map; } }
用法:
Map<String, File> externalLocations = ExternalStorage.getAllStorageLocations(); File sdCard = externalLocations.get(ExternalStorage.SD_CARD); File externalSdCard = externalLocations.get(ExternalStorage.EXTERNAL_SD_CARD);
我有一个使用ListPreference
的应用程序,用户需要select他们想要保存的位置。 在该应用程序中,我扫描了/ proc / mounts和/system/etc/vold.fstab以获取sdcard挂载点。 我将来自每个文件的挂载点存储到两个独立的ArrayList
。
然后,我将一个列表与其他列表中没有列出的其他列表和丢弃列表进行比较。 这给了我一个每个SD卡的根path列表。
从那里,我用File.exists()
, File.isDirectory()
和File.canWrite()
testing了path。 如果这些testing中的任何一个都是错误的,我会从列表中丢弃该path。
无论列表中剩下什么,我都转换为一个String[]
数组,以便它可以被ListPreference
值属性使用。
您可以在这里查看代码: http : //sapienmobile.com/?p=204
为了检索所有外部存储 (无论是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驱动器。
无论如何,请注意,使用硬编码path总是一个不好的方法(特别是当每个制造商可能改变它的喜悦)。
像理查德我也使用/ proc / mounts文件来获取可用的存储选项列表
public class StorageUtils { private static final String TAG = "StorageUtils"; public static class StorageInfo { public final String path; public final boolean internal; public final boolean readonly; public final int display_number; StorageInfo(String path, boolean internal, boolean readonly, int display_number) { this.path = path; this.internal = internal; this.readonly = readonly; this.display_number = display_number; } public String getDisplayName() { StringBuilder res = new StringBuilder(); if (internal) { res.append("Internal SD card"); } else if (display_number > 1) { res.append("SD card " + display_number); } else { res.append("SD card"); } if (readonly) { res.append(" (Read only)"); } return res.toString(); } } public static List<StorageInfo> getStorageList() { List<StorageInfo> list = new ArrayList<StorageInfo>(); String def_path = Environment.getExternalStorageDirectory().getPath(); boolean def_path_internal = !Environment.isExternalStorageRemovable(); String def_path_state = Environment.getExternalStorageState(); boolean def_path_available = def_path_state.equals(Environment.MEDIA_MOUNTED) || def_path_state.equals(Environment.MEDIA_MOUNTED_READ_ONLY); boolean def_path_readonly = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY); BufferedReader buf_reader = null; try { HashSet<String> paths = new HashSet<String>(); buf_reader = new BufferedReader(new FileReader("/proc/mounts")); String line; int cur_display_number = 1; Log.d(TAG, "/proc/mounts"); while ((line = buf_reader.readLine()) != null) { Log.d(TAG, line); if (line.contains("vfat") || line.contains("/mnt")) { StringTokenizer tokens = new StringTokenizer(line, " "); String unused = tokens.nextToken(); //device String mount_point = tokens.nextToken(); //mount point if (paths.contains(mount_point)) { continue; } unused = tokens.nextToken(); //file system List<String> flags = Arrays.asList(tokens.nextToken().split(",")); //flags boolean readonly = flags.contains("ro"); if (mount_point.equals(def_path)) { paths.add(def_path); list.add(0, new StorageInfo(def_path, def_path_internal, readonly, -1)); } else if (line.contains("/dev/block/vold")) { if (!line.contains("/mnt/secure") && !line.contains("/mnt/asec") && !line.contains("/mnt/obb") && !line.contains("/dev/mapper") && !line.contains("tmpfs")) { paths.add(mount_point); list.add(new StorageInfo(mount_point, false, readonly, cur_display_number++)); } } } } if (!paths.contains(def_path) && def_path_available) { list.add(0, new StorageInfo(def_path, def_path_internal, def_path_readonly, -1)); } } catch (FileNotFoundException ex) { ex.printStackTrace(); } catch (IOException ex) { ex.printStackTrace(); } finally { if (buf_reader != null) { try { buf_reader.close(); } catch (IOException ex) {} } } return list; } }
可以通过读取/proc/mounts
(标准Linux文件)并与vold数据( /system/etc/vold.conf
)进行交叉检查来find安装其他SD卡的位置。 并且注意,由Environment.getExternalStorageDirectory()
返回的位置可能不会出现在voldconfiguration中(在某些设备中,它是内部存储,无法卸载),但仍然必须包含在列表中。 但是,我们没有find一个好的方法来向用户描述他们 。
您可以尝试使用名为ContextCompat.getExternalFilesDirs()的支持库函数:
final File[] appsDir=ContextCompat.getExternalFilesDirs(getActivity(),null); final ArrayList<File> extRootPaths=new ArrayList<>(); for(final File file : appsDir) extRootPaths.add(file.getParentFile().getParentFile().getParentFile().getParentFile());
第一个是主要的外部存储,其余的应该是真正的SD卡path。
多个“.getParentFile()”的原因是上一个文件夹,因为原来的path是
.../Android/data/YOUR_APP_PACKAGE_NAME/files/
编辑:这是一个更全面的方式,我已经创build,以获得SD卡path:
/** * 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; } }
我在这个时候尝试所有的解决scheme。 但是,它们都不能在具有一个外部(可拆卸)卡和一个内部(不可拆卸)卡的设备上正常工作。 外部卡的path不可能从“安装”命令,从“proc / mounts”文件等获得
我创build了自己的解决scheme(在Paulo Luan的):
String sSDpath = null; File fileCur = null; for( String sPathCur : Arrays.asList( "ext_card", "external_sd", "ext_sd", "external", "extSdCard", "externalSdCard")) // external sdcard { fileCur = new File( "/mnt/", sPathCur); if( fileCur.isDirectory() && fileCur.canWrite()) { sSDpath = fileCur.getAbsolutePath(); break; } } fileCur = null; if( sSDpath == null) sSDpath = Environment.getExternalStorageDirectory().getAbsolutePath();
只需简单地使用这个:
String primary_sd = System.getenv("EXTERNAL_STORAGE"); if(primary_sd != null) Log.i("EXTERNAL_STORAGE", primary_sd); String secondary_sd = System.getenv("SECONDARY_STORAGE"); if(secondary_sd != null) Log.i("SECONDARY_STORAGE", secondary_sd)
这是我用来find外部卡的方式。 使用mount cmd return然后parsingvfat部分。
String s = ""; try { Process process = new ProcessBuilder().command("mount") .redirectErrorStream(true).start(); process.waitFor(); InputStream is = process.getInputStream(); byte[] buffer = new byte[1024]; while (is.read(buffer) != -1) { s = s + new String(buffer); } is.close(); } catch (Exception e) { e.printStackTrace(); } //用行分隔mount列表String[] lines = s.split("\n"); for(int i=0; i<lines.length; i++) { //如果行内有挂载path且为vfattypes,说明可能是内置或者外置sd的挂载点if(-1 != lines[i].indexOf(path[0]) && -1 != lines[i].indexOf("vfat")) { //再用空格分隔String[] blocks = lines[i].split("\\s"); for(int j=0; j<blocks.length; j++) { //判断是否是挂载为vfattypesif(-1 != blocks[j].indexOf(path[0])) { //Test if it is the external sd card. } } } }
如果你看看android.os.Environment
的源代码,你会发现Android严重依赖于环境variables的path。 您可以使用“SECONDARY_STORAGE”环境variables来查找可移动SD卡的path。
/** * Get a file using an environmental variable. * * @param variableName * The Environment variable name. * @param paths * Any paths to the file if the Environment variable was not found. * @return the File or {@code null} if the File could not be located. */ private static File getDirectory(String variableName, String... paths) { String path = System.getenv(variableName); if (!TextUtils.isEmpty(path)) { if (path.contains(":")) { for (String _path : path.split(":")) { File file = new File(_path); if (file.exists()) { return file; } } } else { File file = new File(path); if (file.exists()) { return file; } } } if (paths != null && paths.length > 0) { for (String _path : paths) { File file = new File(_path); if (file.exists()) { return file; } } } return null; }
用法示例:
public static final File REMOVABLE_STORAGE = getDirectory("SECONDARY_STORAGE");
有没有一种通用的方式来find外部SD卡的位置?
通用的方式 ,如果你是官方的方式; 是的,有一个。
在API级别19中,即在Android 4.4版Kitkat中,他们在Context
Class中添加了File[] getExternalFilesDirs (String type)
,允许应用程序将数据/文件存储在micro SD卡中。
Android 4.4是该平台的第一个版本,实际上允许应用程序使用SD卡进行存储。 在API级别19之前,任何对SD卡的访问都是通过私有的,不受支持的API实现的。
getExternalFilesDirs(String type)返回所有共享/外部存储设备上特定于应用程序的目录的绝对path。 这意味着,它将返回内部和外部存储器的path。 通常, 第二个返回的path将是microSD卡的存储path(如果有的话)。
但是请注意,
共享存储可能不总是可用的,因为可移动介质可以被用户popup。 媒体状态可以使用
getExternalStorageState(File)
进行检查。这些文件没有强制执行。 例如,任何持有
WRITE_EXTERNAL_STORAGE
应用程序WRITE_EXTERNAL_STORAGE
可以写入这些文件。
根据Google /官方Android文档的内部和外部存储术语与我们所认为的完全不同 。
由于我上面的原始答案,扫描vold不再是各个制造商可行的。
我开发了一个更可靠和直接的方法。
File mnt = new File("/storage"); if (!mnt.exists()) mnt = new File("/mnt"); File[] roots = mnt.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { return pathname.isDirectory() && pathname.exists() && pathname.canWrite() && !pathname.isHidden() && !isSymlink(pathname); } });
根将包含系统上所有可写入的根目录,包括任何连接USB的USB设备。
注意:canWrite方法需要android.permission.WRITE_EXTERNAL_STORAGE权限。
这个解决scheme处理的事实, System.getenv("SECONDARY_STORAGE")
是没有用棉花糖。
经过testing和工作:
- Samsung Galaxy Tab 2(Android 4.1.1 – 股票)
- 三星Galaxy Note 8.0(Android 4.2.2 – 股票)
- 三星Galaxy S4(Android 4.4 – 股票)
- 三星Galaxy S4(Android 5.1.1 – Cyanogenmod)
-
三星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; }
它已经这么晚了,但最后我得到了一些东西,我testing了大多数设备(由制造商和Android版本)在Android 2.2以上的工作。 如果您发现它不起作用,请用您的设备名称进行注释。 我会修好它。 如果有人感兴趣,我会解释它是如何工作的。
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStreamReader; import android.util.Log; /** * @author ajeet *05-Dec-2014 2014 * */ public class StorageUtil { public boolean isRemovebleSDCardMounted() { File file = new File("/sys/class/block/"); File[] files = file.listFiles(new MmcblkFilter("mmcblk\\d$")); boolean flag = false; for (File mmcfile : files) { File scrfile = new File(mmcfile, "device/scr"); if (scrfile.exists()) { flag = true; break; } } return flag; } public String getRemovebleSDCardPath() throws IOException { String sdpath = null; File file = new File("/sys/class/block/"); File[] files = file.listFiles(new MmcblkFilter("mmcblk\\d$")); String sdcardDevfile = null; for (File mmcfile : files) { Log.d("SDCARD", mmcfile.getAbsolutePath()); File scrfile = new File(mmcfile, "device/scr"); if (scrfile.exists()) { sdcardDevfile = mmcfile.getName(); Log.d("SDCARD", mmcfile.getName()); break; } } if (sdcardDevfile == null) { return null; } FileInputStream is; BufferedReader reader; files = file.listFiles(new MmcblkFilter(sdcardDevfile + "p\\d+")); String deviceName = null; if (files.length > 0) { Log.d("SDCARD", files[0].getAbsolutePath()); File devfile = new File(files[0], "dev"); if (devfile.exists()) { FileInputStream fis = new FileInputStream(devfile); reader = new BufferedReader(new InputStreamReader(fis)); String line = reader.readLine(); deviceName = line; } Log.d("SDCARD", "" + deviceName); if (deviceName == null) { return null; } Log.d("SDCARD", deviceName); final File mountFile = new File("/proc/self/mountinfo"); if (mountFile.exists()) { is = new FileInputStream(mountFile); reader = new BufferedReader(new InputStreamReader(is)); String line = null; while ((line = reader.readLine()) != null) { // Log.d("SDCARD", line); // line = reader.readLine(); // Log.d("SDCARD", line); String[] mPonts = line.split("\\s+"); if (mPonts.length > 6) { if (mPonts[2].trim().equalsIgnoreCase(deviceName)) { if (mPonts[4].contains(".android_secure") || mPonts[4].contains("asec")) { continue; } sdpath = mPonts[4]; Log.d("SDCARD", mPonts[4]); } } } } } return sdpath; } static class MmcblkFilter implements FilenameFilter { private String pattern; public MmcblkFilter(String pattern) { this.pattern = pattern; } @Override public boolean accept(File dir, String filename) { if (filename.matches(pattern)) { return true; } return false; } } }
I don't know why but I need to call .createNewFile() on a File created in the public storage directories before using it. In the framework the comments for that method say it isn't useful. Here's a sample…
String myPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PODCASTS) + File.separator + "My Directory"; final File myDir = new File(myPath); try { myDir.mkdirs(); } catch (Exception ex) { Toast.makeText(this, "error: " + ex.getMessage(), Toast.LENGTH_LONG).show(); }
String myPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PODCASTS) + File.separator + "My Directory"; final File myDir = new File(myPath); try { myDir.mkdirs(); } catch (Exception ex) { Toast.makeText(this, "error: " + ex.getMessage(), Toast.LENGTH_LONG).show(); }
String fname = "whatever"; File newFile = new File(myDir, fname); Log.i(TAG, "File exists --> " + newFile.exists()) //will be false try { if (newFile.createNewFile()) { //continue } else { Log.e(TAG, "error creating file"); } } catch (Exception e) { Log.e(TAG, e.toString()); }
I have created a utils method to check a SD card is available on device or not, and get SD card path on device if it available.
You can copy 2 methods bellow into your project's class that you need. 就这样。
public String isRemovableSDCardAvailable() { final String FLAG = "mnt"; final String SECONDARY_STORAGE = System.getenv("SECONDARY_STORAGE"); final String EXTERNAL_STORAGE_DOCOMO = System.getenv("EXTERNAL_STORAGE_DOCOMO"); final String EXTERNAL_SDCARD_STORAGE = System.getenv("EXTERNAL_SDCARD_STORAGE"); final String EXTERNAL_SD_STORAGE = System.getenv("EXTERNAL_SD_STORAGE"); final String EXTERNAL_STORAGE = System.getenv("EXTERNAL_STORAGE"); Map<Integer, String> listEnvironmentVariableStoreSDCardRootDirectory = new HashMap<Integer, String>(); listEnvironmentVariableStoreSDCardRootDirectory.put(0, SECONDARY_STORAGE); listEnvironmentVariableStoreSDCardRootDirectory.put(1, EXTERNAL_STORAGE_DOCOMO); listEnvironmentVariableStoreSDCardRootDirectory.put(2, EXTERNAL_SDCARD_STORAGE); listEnvironmentVariableStoreSDCardRootDirectory.put(3, EXTERNAL_SD_STORAGE); listEnvironmentVariableStoreSDCardRootDirectory.put(4, EXTERNAL_STORAGE); File externalStorageList[] = null; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { externalStorageList = getContext().getExternalFilesDirs(null); } String directory = null; int size = listEnvironmentVariableStoreSDCardRootDirectory.size(); for (int i = 0; i < size; i++) { if (externalStorageList != null && externalStorageList.length > 1 && externalStorageList[1] != null) directory = externalStorageList[1].getAbsolutePath(); else directory = listEnvironmentVariableStoreSDCardRootDirectory.get(i); directory = canCreateFile(directory); if (directory != null && directory.length() != 0) { if (i == size - 1) { if (directory.contains(FLAG)) { Log.e(getClass().getSimpleName(), "SD Card's directory: " + directory); return directory; } else { return null; } } Log.e(getClass().getSimpleName(), "SD Card's directory: " + directory); return directory; } } return null; } /** * Check if can create file on given directory. Use this enclose with method * {@link BeginScreenFragement#isRemovableSDCardAvailable()} to check sd * card is available on device or not. * * @param directory * @return */ public String canCreateFile(String directory) { final String FILE_DIR = directory + File.separator + "hoang.txt"; File tempFlie = null; try { tempFlie = new File(FILE_DIR); FileOutputStream fos = new FileOutputStream(tempFlie); fos.write(new byte[1024]); fos.flush(); fos.close(); Log.e(getClass().getSimpleName(), "Can write file on this directory: " + FILE_DIR); } catch (Exception e) { Log.e(getClass().getSimpleName(), "Write file error: " + e.getMessage()); return null; } finally { if (tempFlie != null && tempFlie.exists() && tempFlie.isFile()) { // tempFlie.delete(); tempFlie = null; } } return directory; }
Its work for all external devices, But make sure only get external device folder name and then you need to get file from given location using File class.
public static List<String> getExternalMounts() { final List<String> out = new ArrayList<>(); 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; }
Calling:
List<String> list=getExternalMounts(); if(list.size()>0) { String[] arr=list.get(0).split("/"); int size=0; if(arr!=null && arr.length>0) { size= arr.length - 1; } File parentDir=new File("/storage/"+arr[size]); if(parentDir.listFiles()!=null){ File parent[] = parentDir.listFiles(); for (int i = 0; i < parent.length; i++) { // get file path as parent[i].getAbsolutePath()); } } }
Getting access to external storage
In order to read or write files on the external storage, your app must acquire the READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE system permissions. 例如:
<manifest ...> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> ... </manifest>
/sdcard => Internal Storage (It's a symlink but should work)
/mnt/extSdCard => External Sdcard
This is for Samsung Galaxy S3
You can probably bank on this being true for most…double check however!