Android 的外部 SDCard 文件路径

Posted

技术标签:

【中文标题】Android 的外部 SDCard 文件路径【英文标题】:External SDCard file path for Android 【发布时间】:2014-06-01 03:40:59 【问题描述】:

android设备上外部SDCard的文件路径是否总是"/storage/extSdCard"?如果没有,有多少种变化?

我的应用需要它来测试外部 SDCard 的可用性。

我正在使用 Titanium,它有一个方法 Titanium.Filesystem.isExternalStoragePresent( ) 但即使没有安装外部 SDCard,它也总是返回 true。

我认为它在本地存储中检测到 SDCard,因此返回 true。但我真正想要的是检测是否安装了物理 SDCard。

我可以通过单独检测文件 "/storage/extSdCard" 的存在来做到这一点吗?

谢谢。

【问题讨论】:

Android 没有完整的公共方法来查询外部 sdcard,并且由于每个制造商都有自己定义“外部”sdcard 的方式,因此您需要获取不同的设备并对其进行测试确定如何为每个定义外部 sdcard。 【参考方案1】:

Android设备上外部SDCard的文件路径总是“/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";
            
        
    

但我真正想要的是检测是否安装了物理 SDCard。

我还没有尝试过代码,但是 Dmitriy Lozenko 在answer 中的方法更有趣。 他的方法返回系统上所有安装的 SD 卡的路径,无论制造商如何

【讨论】:

参考您上面的代码,我可以假设所有制造商的外部 SD 卡文件路径都必须包含关键字“extSdCard”或“external”吗? @Bowie 在我写这段代码的时候,我只和三星核实过,我无法为其他制造商确认。您是否尝试过 Dmitriy Lozenko 的代码?如果您想要所有制造商的 sd 卡路径,这是一种更好的方法。 我没有,因为问题是我使用 Titanium 来开发我的应用程序。它使我远离较低级别的编码。 (到目前为止)我唯一能做的就是使用它提供的方法来获取检测到的 SDCard 文件路径。 对不起,我错过了您使用的是 Titanium。在这种情况下,可能值得创建一个 Titanium module 来集成此本机代码。【参考方案2】:

这就是我最终使用 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;
    

【讨论】:

【参考方案3】:

希望对你有用:)

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;
    

【讨论】:

【参考方案4】:

我刚刚想通了一些事情。至少对于我的 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 会有它的路径。如果没有,它将是一个空字符串。

【讨论】:

【参考方案5】:

我在 4 天后得到了解决方案,请在 Android(Java) 中为 File 类提供路径时注意以下几点:

    使用内部存储字符串的路径 path="/storage/sdcard0/myfile.txt"; 使用外部存储路径 path="/storage/sdcard1/myfile.txt"; 在 Manifest 文件中提及权限。

&lt;uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /&gt;

&lt;uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /&gt;

    首先检查文件长度以确认。 检查 ES 文件资源管理器中有关 sdcard0 和 sdcard1 的路径是 还是一样……

例如:

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

【讨论】:

但是上面提到的都是外部存储路径。甚至手机内存............!它也适用于 Micromax

以上是关于Android 的外部 SDCard 文件路径的主要内容,如果未能解决你的问题,请参考以下文章

android-数据存储之外部file存储(sdcard)

android文件系统管理全解析——内部存储和外部存储 /data/data和/sdcard/Android/data区别

Android 10:我都有哪些选择可以将外部存储上的文件保存到名为“/sdcard/my-app/”的目录中

Unity Android 之 读取下载获取移动端 sdcard 路径下的指定文件夹的所有图片的几种方式的简单整理

在android的Webview中加载sdcard pdf文件

如何在 Android 上的 SDCard 上打开 HTML 文件