有没有一种通用的方法来找到外置SD卡的位置?
请不要与外部存储混淆。
Environment.getExternalStorageState()返回内部SD挂载点的路径,例如/mnt/sdcard。但问题是关于外部SD的。我如何获得类似/mnt/sdcard/external_sd的路径(它可能因设备而异)?
我想我将以根据文件系统名称过滤mount命令的输出作为结束。但我不确定这种方式是否足够稳健。
有没有一种通用的方法来找到外置SD卡的位置?
请不要与外部存储混淆。
Environment.getExternalStorageState()返回内部SD挂载点的路径,例如/mnt/sdcard。但问题是关于外部SD的。我如何获得类似/mnt/sdcard/external_sd的路径(它可能因设备而异)?
我想我将以根据文件系统名称过滤mount命令的输出作为结束。但我不确定这种方式是否足够稳健。
当前回答
通过编写下面的代码,您将获得位置:
数据存储663D-554E / Android / app_package_name / files /
存储你的应用程序数据在/android/数据位置内的sd_card。
File[] list = ContextCompat.getExternalFilesDirs(MainActivity.this, null);
list[1]+"/fol"
对于获取位置,内部传递0,sdcard传递1到文件数组。
我已经在moto g4 plus和三星设备上测试了这段代码(一切正常)。
希望这对你有所帮助。
其他回答
像Richard一样,我也使用/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;
}
}
根据这里找到的一些答案,我想出了以下解决方案。
代码:
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);
我找到的唯一有效的解决方案是使用反射
/**
* Get external sd card path using reflection
* @param mContext
* @param is_removable is external storage removable
* @return
*/
private static String getExternalStoragePath(Context mContext, boolean is_removable) {
StorageManager mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
Class<?> storageVolumeClazz = null;
try {
storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");
Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList");
Method getPath = storageVolumeClazz.getMethod("getPath");
Method isRemovable = storageVolumeClazz.getMethod("isRemovable");
Object result = getVolumeList.invoke(mStorageManager);
final int length = Array.getLength(result);
for (int i = 0; i < length; i++) {
Object storageVolumeElement = Array.get(result, i);
String path = (String) getPath.invoke(storageVolumeElement);
boolean removable = (Boolean) isRemovable.invoke(storageVolumeElement);
if (is_removable == removable) {
return path;
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
这么晚了,但最终我得到了一些东西,我已经测试了大多数设备(通过制造商和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;
}
}
}
这次我尝试了这个主题内的所有解决方案。但是,在有一个外置卡(可移动)和一个内置卡(不可移动)的设备上,所有这些设备都不能正常工作。外部卡的路径不可能从'mount'命令,从'proc/mounts'文件等。
我在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();