2013-08-05 47 views
11

我有一个预先存储在SD卡中的大量数据的应用程序。在Android中获取外部SDCard位置

我们支持所有平板电脑ICS。我无法找到在所有设备上正确访问SDCard位置的方法。

我看了这里给出的各种解决方案,但他们似乎并不适用于所有情况。寻找一个通用的解决方案。

即使任何人都可以告诉我所有可能的SDCard挂载点。

我只针对android平板电脑,如果这可以缩小解决方案。

+2

http://developer.android.com/guide/topics/data/data-storage.html。检查使用外部存储下的主题,如果它有帮助 – Raghunandan

+0

@Raghunandan:我已经尝试了那里给出的方法,但他们似乎并没有到处工作。在大多数平板电脑中,它会返回不是sdcard位置的/ mnt/sdcard。 – phoenixwizard

+0

http://stackoverflow.com/questions/16637935/a-safe-path-to-external-storage/16638064#16638064。我不会在链接中推荐解决方案。你可以试试看,但我建议你按照文档。 – Raghunandan

回答

15

不幸的是,这是一个常见的问题,因为Android设备高度分散。 Environment.getExternalStorageDirectory()是指设备制造商认为是“外部存储”的任何设备。在某些设备上,这是可移动媒体,如SD卡。在某些设备上,这是部分设备上的闪存(http://developer.android.com/reference/android/os/Environment.html#getExternalStorageDirectory())此处,“外部存储”表示“驱动器安装在主机上时可通过USB Mass Storage模式访问”。 如果设备制造商选择使用外置存储器作为板载闪存并且也有SD卡,则需要联系该制造商以确定您是否可以使用SD卡。对于大多数符合条件的Android设备(从Google合规性列表中已知的),Environment.getExternalStorageDirectory()应该可以工作。或者您可以编写一个自定义存储类,查看挂载点并为您提供安装的SDCard的正确路径。这是我已经实施并且迄今为止已经工作。

public class StorageOptions { 
    private static ArrayList<String> mMounts = new ArrayList<String>(); 
    private static ArrayList<String> mVold = new ArrayList<String>(); 

    public static String[] labels; 
    public static String[] paths; 
    public static int count = 0; 
    private static final String TAG = StorageOptions.class.getSimpleName(); 

    public static void determineStorageOptions() { 
     readMountsFile(); 

     readVoldFile(); 

     compareMountsWithVold(); 

     testAndCleanMountsList(); 

     setProperties(); 
    } 

    private static void readMountsFile() { 
     /* 
     * Scan the /proc/mounts file and look for lines like this: 
     * /dev/block/vold/179:1 /mnt/sdcard vfat 
     * rw,dirsync,nosuid,nodev,noexec, 
     * relatime,uid=1000,gid=1015,fmask=0602,dmask 
     * =0602,allow_utime=0020,codepage 
     * =cp437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 0 
     * 
     * When one is found, split it into its elements and then pull out the 
     * path to the that mount point and add it to the arraylist 
     */ 

     // some mount files don't list the default 
     // path first, so we add it here to 
     // ensure that it is first in our list 
     mMounts.add("/mnt/sdcard"); 

     try { 
      Scanner scanner = new Scanner(new File("/proc/mounts")); 
      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) { 
      // Auto-generated catch block 

      e.printStackTrace(); 
     } 
    } 

    private static void readVoldFile() { 
     /* 
     * Scan the /system/etc/vold.fstab file and look for lines like this: 
     * dev_mount sdcard /mnt/sdcard 1 
     * /devices/platform/s3c-sdhci.0/mmc_host/mmc0 
     * 
     * When one is found, split it into its elements and then pull out the 
     * path to the that mount point and add it to the arraylist 
     */ 

     // some devices are missing the vold file entirely 
     // so we add a path here to make sure the list always 
     // includes the path to the first sdcard, whether real 
     // or emulated. 
     mVold.add("/mnt/sdcard"); 

     try { 
      Scanner scanner = new Scanner(new File("/system/etc/vold.fstab")); 
      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(":")); 

        // don't add the default vold path 
        // it's already in the list. 
        if (!element.equals("/mnt/sdcard")) 
         mVold.add(element); 
       } 
      } 
     } catch (Exception e) { 
      // Auto-generated catch block 

      e.printStackTrace(); 
     } 
    } 

    private static void compareMountsWithVold() { 
     /* 
     * Sometimes the two lists of mount points will be different. We only 
     * want those mount points that are in both list. 
     * 
     * Compare the two lists together and remove items that are not in both 
     * lists. 
     */ 

     for (int i = 0; i < mMounts.size(); i++) { 
      String mount = mMounts.get(i); 
      if (!mVold.contains(mount)) 
       mMounts.remove(i--); 
     } 

     // don't need this anymore, clear the vold list to reduce memory 
     // use and to prepare it for the next time it's needed. 
     mVold.clear(); 
    } 

    private static void testAndCleanMountsList() { 
     /* 
     * Now that we have a cleaned list of mount paths Test each one to make 
     * sure it's a valid and available path. If it is not, remove it from 
     * the list. 
     */ 

     for (int i = 0; i < mMounts.size(); i++) { 
      String mount = mMounts.get(i); 
      File root = new File(mount); 
      if (!root.exists() || !root.isDirectory() || !root.canWrite()) 
       mMounts.remove(i--); 
     } 
    } 

    @SuppressWarnings("unchecked") 
    private static void setProperties() { 
     /* 
     * At this point all the paths in the list should be valid. Build the 
     * public properties. 
     */ 
     Constants.mMounts = new ArrayList<String>(); 
     ArrayList<String> mLabels = new ArrayList<String>(); 

     int j = 0; 
     if (mMounts.size() > 0) { 
      if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) 
       mLabels.add("Auto"); 
      else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { 
       if (Environment.isExternalStorageRemovable()) { 
        mLabels.add("External SD Card 1"); 
        j = 1; 
       } else 
        mLabels.add("Internal Storage"); 
      } else { 
       if (!Environment.isExternalStorageRemovable() 
         || Environment.isExternalStorageEmulated()) 
        mLabels.add("Internal Storage"); 
       else { 
        mLabels.add("External SD Card 1"); 
        j = 1; 
       } 
      } 

      if (mMounts.size() > 1) { 
       for (int i = 1; i < mMounts.size(); i++) { 
        mLabels.add("External SD Card " + (i + j)); 
       } 
      } 
     } 

     labels = new String[mLabels.size()]; 
     mLabels.toArray(labels); 

     paths = new String[mMounts.size()]; 
     mMounts.toArray(paths); 
     Constants.mMounts = (ArrayList<String>) mMounts.clone(); 
     Constants.mLabels = (ArrayList<String>) mLabels.clone(); 
     count = Math.min(labels.length, paths.length); 

     // don't need this anymore, clear the mounts list to reduce memory 
     // use and to prepare it for the next time it's needed. 
     mMounts.clear(); 

    } 
} 

我发现这掀起了类似的问题,从这样,那我没有链接不幸,但它在那儿可能对索尼的Android开发者网站(无链接有两种不幸)。 Wagic - 一个C++游戏引擎库实现相同,他们的代码在这里:http://wagic.googlecode.com/svn-history/r4300/trunk/projects/mtg/Android/src/net/wagic/utils/StorageOptions.java 所以你可以看看实现。我希望从谷歌有人能回答这个问题,并提供所有Android设备读取SD卡安装点单方式

+0

只有一个疑问。从哪里得到Constants.mMounts? – phoenixwizard

+0

对不起,这是我的实现特定的类 - 一个持有所有应用程序常量,不需要你,你可以实现自己的 – Slartibartfast

+1

它似乎没有考虑与/ mnt/extsd的标签:( – phoenixwizard

-1

如果你想获取路径到SD卡中使用此代码

String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath();

然后用它来获得特定文件夹的路径/文件

String path = baseDir + "/your folder(s)/" + fileName;

+3

这在所有设备中都无效。 – phoenixwizard

-6

这很简单。

String f = Environment.getExternalStorageDirectory().getAbsolutePath(); 
Log.v("TAG",f);//to print the path of sdcard 

如果你想访问一个文件,然后。

String f = Environment.getExternalStorageDirectory()+"/file.ext"; 
Log.v("TAG",f);//to print the path of file in Logcat. 
+1

请提供文档或教程的链接,并确保您已经回答了“适用于所有设备”的问题 – Tala

+0

我已经尝试过。它适用于所有设备。 – Prakhar

+1

@Prakhar它在许多设备上都不适用于我。 – phoenixwizard

0
你所想

它不是简单的, 字符串型F = Environment.getExternalStorageDirectory()getAbsolutePath()。 (“TAG”,f); //打印sdcard的路径

它返回的设备存储路径不是外部sdcard路径。