查找可移动SD卡的位置

219

有没有一种通用的方法来查找外部SD卡的位置?

请不要与外部存储混淆。

Environment.getExternalStorageState()返回内部SD挂载点的路径,例如/mnt/sdcard。但是问题是关于外部SD卡的。我怎么才能获得像/mnt/sdcard/external_sd这样的路径(它可能因设备而异)?

我想我最终会通过文件系统名称过滤mount命令的输出。但我不确定这种方法是否足够健壮。


这是我的解决方案,适用于Nougat版本:https://dev59.com/Npbfa4cB1Zd3GeqPrk7J#40205116 - Gokul NC
"Environment.getExternalStorageState() 返回指向内部SD挂载点的路径,例如“/mnt/sdcard”。嗯,从Android的角度来说,它并不是内部的。我相信你要找的术语是“不可移除的”(not removable)。" - LarsH
1
adb shell echo $EXTERNAL_STORAGE - Charles L.
25个回答

0
我已经创建了一个工具方法来检查设备上是否有可用的SD卡,并在设备上获取SD卡路径(如果它可用)。
您可以将下面的2个方法复制到您需要的项目类中。就这样。
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;
}

0
这是所有可靠方法的结论,适用于所有安卓版本(希望如此)。
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",
        "EXTERNAL_STORAGE_DOCOMO",
        "EXTERNAL_SDCARD_STORAGE",
        "EXTERNAL_SD_STORAGE",
        // add more if you have :-D
    })
    {
        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上进行了测试。 您应该在每个版本上进行测试,并在下方评论中指出任何不兼容的情况,以便我们进行改进。

-1

它适用于所有外部设备,但请确保仅获取外部设备文件夹名称,然后使用File类从给定位置获取文件。

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;
    }

调用:

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());

                }
            }
        }

获取外部存储器的访问权限

为了在外部存储器上读取或写入文件,您的应用程序必须获取READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE系统权限。例如:

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

-1

这是我找到外部存储路径的方法。

public static String getExternalStoragePath(Context context){
        File[] f = ContextCompat.getExternalFilesDirs(context, null);
        String internalPath = Environment.getExternalStorageDirectory().getAbsolutePath();
        String excessive = "";
        String externalPath = "";
        for (File file : f) {
            if (file.getAbsolutePath().startsWith(internalPath)) {
                excessive = file.getAbsolutePath().replaceAll(internalPath, "");
            }
        }
        for (File file : f) {
            if (!file.getAbsolutePath().startsWith(excessive)) {
                externalPath = file.getAbsolutePath().replaceAll(excessive, "");
            }
        }
        return  externalPath;
    }

-2

/sdcard => 内部存储(这是一个符号链接,但应该有效)

/mnt/extSdCard => 外部SD卡

这适用于三星Galaxy S3

大多数情况下这应该是正确的...不过最好再确认一下!


8
我曾经拥有过几款不同的安卓手机,其中约一半是三星品牌,但我从来没有见过这个位置被使用过。或许在S3上是真的存在,但说“你可以肯定大多数情况下也是如此”是完全错误的。 - Geobits
错误。/sdcard 是我的索尼2305上外部链接。 - jiggunjer
2
我不是说可能不是吗? - robbyoconnor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接