Android的外部SD卡文件路径

21

在Android设备上,外部SD卡的文件路径总是"/storage/extSdCard"吗?如果不是,请问还有多少种变化?

我需要这个信息来测试外部SD卡的可用性。

我正在使用Titanium开发,它有一个方法Titanium.Filesystem.isExternalStoragePresent(),但即使外部SD卡未挂载,它也总是返回true。

我认为它是在本地存储中检测SD卡,因此返回true。但我真正想要的是检测物理SD卡是否已挂载。

我能否通过仅检测文件"/storage/extSdCard"的存在来实现此目的?

谢谢。


Android没有一个完美的公共方法来查询外部SD卡,而且由于每个制造商都有自己定义“外部”SD卡的方式,因此您需要获取不同的设备并对它们进行测试,以确定每个设备如何定义外部SD卡。 - ChuongPham
5个回答

10
很遗憾,Android设备上外部SD卡的文件路径并不总是"/storage/extSdCard"。每个制造商的路径可能都不同。使用Environment.getExternalStorageDirectory()会返回SD卡的正常路径mnt/sdcard/。但是对于三星设备来说,SD卡的路径可能在mnt/extSdCard/mnt/external_sd/下。
因此,一种解决方法是根据每个制造商使用的路径检查外部目录的存在性。可以使用以下代码:
mExternalDirectory = Environment.getExternalStorageDirectory()
            .getAbsolutePath();
    if (android.os.Build.DEVICE.contains("samsung")
            || android.os.Build.MANUFACTURER.contains("samsung")) {
        File f = new File(Environment.getExternalStorageDirectory()
                .getParent() + "/extSdCard" + "/myDirectory");
        if (f.exists() && f.isDirectory()) {
            mExternalDirectory = Environment.getExternalStorageDirectory()
                    .getParent() + "/extSdCard";
        } else {
            f = new File(Environment.getExternalStorageDirectory()
                    .getAbsolutePath() + "/external_sd" + "/myDirectory");  
            if (f.exists() && f.isDirectory()) {
                mExternalDirectory = Environment
                        .getExternalStorageDirectory().getAbsolutePath()
                        + "/external_sd";
            }
        }
    }

但是我真正想要的是检测物理SD卡是否已挂载。

我尚未尝试过这段代码,但 Dmitriy Lozenko 在这个答案中的方法更有趣。 他的方法返回系统上所有已挂载SD卡的路径,无论制造商如何


参考您上面的代码,我可以假设所有制造商的外部SD卡文件路径都必须包含关键字"extSdCard"或"external",对吗? - Bowie
@Bowie 在我编写这段代码时,我只检查了三星手机,无法确认其他制造商。你试过 Dmitriy Lozenko 的代码吗?如果你想获取所有制造商的 SD 卡路径,那是更好的方法。 - Digoun
我没有这样做的原因是我正在使用Titanium来开发我的应用程序。它让我远离底层编码。到目前为止,我唯一能做的就是使用它提供的方法来获取检测到的SD卡文件路径。 - Bowie
很抱歉我之前没注意到你在使用Titanium。在这种情况下,可以考虑创建一个Titanium模块,将此原生代码整合进去。 - Digoun

5
这是我最终使用的方法获取sdcard路径:
public String getExternalStoragePath() {

        String internalPath = Environment.getExternalStorageDirectory().getAbsolutePath();
        String[] paths = internalPath.split("/");
        String parentPath = "/";
        for (String s : paths) {
            if (s.trim().length() > 0) {
                parentPath = parentPath.concat(s);
                break;
            }
        }
        File parent = new File(parentPath);
        if (parent.exists()) {
            File[] files = parent.listFiles();
            for (File file : files) {
                String filePath = file.getAbsolutePath();
                Log.d(TAG, filePath);
                if (filePath.equals(internalPath)) {
                    continue;
                } else if (filePath.toLowerCase().contains("sdcard")) {
                    return filePath;
                } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    try {
                        if (Environment.isExternalStorageRemovable(file)) {
                            return filePath;
                        }
                    } catch (RuntimeException e) {
                        Log.e(TAG, "RuntimeException: " + e);
                    }
                }
            }

        }
        return null;
    }

4
我希望您会发现这对您有所帮助 :)
import android.os.Environment;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;


public class MemoryStorage {

    private MemoryStorage() {}

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

3

我刚刚想到了一个东西。至少在我的Android模拟器上,我将SD卡路径设为 ' /storage/????-???? ',其中每个?都是大写字母或数字。

因此,如果/storage/目录中有一个可读取的目录,并且它不是内部存储目录,那么它一定是SD卡。

我的代码在Android模拟器上运行良好!

String removableStoragePath;
    File fileList[] = new File("/storage/").listFiles();
    for (File file : fileList)
  {     if(!file.getAbsolutePath().equalsIgnoreCase(Environment.getExternalStorageDirectory().getAbsolutePath()) && file.isDirectory() && file.canRead())
        removableStoragePath = file.getAbsolutePath();  }
    //If there is an SD Card, removableStoragePath will have it's path. If there isn't it will be an empty string.

如果存在SD卡,removableStoragePath将会有其路径。如果不存在,则为空字符串。

3

经过4天的努力,我终于找到了解决方法。在为Android(Java)中的File类指定路径时,请注意以下几点:

  1. 对于内部存储,请使用以下路径字符串: path="/storage/sdcard0/myfile.txt";
  2. 对于外部存储,请使用以下路径字符串: path="/storage/sdcard1/myfile.txt";
  3. 请在清单文件中声明相关权限。

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

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

  1. 确认文件长度是否正确。
  2. 在ES文件浏览器中检查sdcard0和sdcard1路径是否相同。

例如:

File file = new File(path);
long = file.length();//in Bytes

然而,上述两者都是外部存储路径。即使是手机的内部存储器……它在Micromax中也可以工作。 - Mahadev Mane

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