How can I get the external SD card path for Android 4.0+?

前端 未结 26 2691
清歌不尽
清歌不尽 2020-11-22 04:48

Samsung Galaxy S3 has an external SD card slot, which is mounted to /mnt/extSdCard.

How can I get this path by something like Environment.getExter

相关标签:
26条回答
  • 2020-11-22 05:35

    Good news! In KitKat there's now a public API for interacting with these secondary shared storage devices.

    The new Context.getExternalFilesDirs() and Context.getExternalCacheDirs() methods can return multiple paths, including both primary and secondary devices. You can then iterate over them and check Environment.getStorageState() and File.getFreeSpace() to determine the best place to store your files. These methods are also available on ContextCompat in the support-v4 library.

    Also note that if you're only interested in using the directories returned by Context, you no longer need the READ_ or WRITE_EXTERNAL_STORAGE permissions. Going forward, you'll always have read/write access to these directories with no additional permissions required.

    Apps can also continue working on older devices by end-of-lifing their permission request like this:

    <uses-permission
        android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        android:maxSdkVersion="18" />
    
    0 讨论(0)
  • 2020-11-22 05:38
     String path = Environment.getExternalStorageDirectory()
                            + File.separator + Environment.DIRECTORY_PICTURES;
                    File dir = new File(path);
    
    0 讨论(0)
  • 2020-11-22 05:39

    On Galaxy S3 Android 4.3 the path I use is ./storage/extSdCard/Card/ and it does the job. Hope it helps,

    0 讨论(0)
  • 2020-11-22 05:40

    Here's how I get the list of SD-card paths (excluding the primary external storage) :

      /**
       * returns a list of all available sd cards paths, or null if not found.
       * 
       * @param includePrimaryExternalStorage set to true if you wish to also include the path of the primary external storage
       */
      @TargetApi(Build.VERSION_CODES.HONEYCOMB)
      public static List<String> getSdCardPaths(final Context context,final boolean includePrimaryExternalStorage)
        {
        final File[] externalCacheDirs=ContextCompat.getExternalCacheDirs(context);
        if(externalCacheDirs==null||externalCacheDirs.length==0)
          return null;
        if(externalCacheDirs.length==1)
          {
          if(externalCacheDirs[0]==null)
            return null;
          final String storageState=EnvironmentCompat.getStorageState(externalCacheDirs[0]);
          if(!Environment.MEDIA_MOUNTED.equals(storageState))
            return null;
          if(!includePrimaryExternalStorage&&VERSION.SDK_INT>=VERSION_CODES.HONEYCOMB&&Environment.isExternalStorageEmulated())
            return null;
          }
        final List<String> result=new ArrayList<>();
        if(includePrimaryExternalStorage||externalCacheDirs.length==1)
          result.add(getRootOfInnerSdCardFolder(externalCacheDirs[0]));
        for(int i=1;i<externalCacheDirs.length;++i)
          {
          final File file=externalCacheDirs[i];
          if(file==null)
            continue;
          final String storageState=EnvironmentCompat.getStorageState(file);
          if(Environment.MEDIA_MOUNTED.equals(storageState))
            result.add(getRootOfInnerSdCardFolder(externalCacheDirs[i]));
          }
        if(result.isEmpty())
          return null;
        return result;
        }
    
      /** Given any file/folder inside an sd card, this will return the path of the sd card */
      private static String getRootOfInnerSdCardFolder(File file)
        {
        if(file==null)
          return null;
        final long totalSpace=file.getTotalSpace();
        while(true)
          {
          final File parentFile=file.getParentFile();
          if(parentFile==null||parentFile.getTotalSpace()!=totalSpace||!parentFile.canRead())
            return file.getAbsolutePath();
          file=parentFile;
          }
        }
    
    0 讨论(0)
  • 2020-11-22 05:42

    I found more reliable way to get paths to all SD-CARDs in system. This works on all Android versions and return paths to all storages (include emulated).

    Works correctly on all my devices.

    P.S.: Based on source code of Environment class.

    private static final Pattern DIR_SEPORATOR = Pattern.compile("/");
    
    /**
     * Raturns all available SD-Cards in the system (include emulated)
     *
     * Warning: Hack! Based on Android source code of version 4.3 (API 18)
     * Because there is no standart way to get it.
     * TODO: Test on future Android versions 4.4+
     *
     * @return paths to all available SD-Cards in the system (include emulated)
     */
    public static String[] getStorageDirectories()
    {
        // Final set of paths
        final Set<String> rv = new HashSet<String>();
        // Primary physical SD-CARD (not emulated)
        final String rawExternalStorage = System.getenv("EXTERNAL_STORAGE");
        // All Secondary SD-CARDs (all exclude primary) separated by ":"
        final String rawSecondaryStoragesStr = System.getenv("SECONDARY_STORAGE");
        // Primary emulated SD-CARD
        final String rawEmulatedStorageTarget = System.getenv("EMULATED_STORAGE_TARGET");
        if(TextUtils.isEmpty(rawEmulatedStorageTarget))
        {
            // Device has physical external storage; use plain paths.
            if(TextUtils.isEmpty(rawExternalStorage))
            {
                // EXTERNAL_STORAGE undefined; falling back to default.
                rv.add("/storage/sdcard0");
            }
            else
            {
                rv.add(rawExternalStorage);
            }
        }
        else
        {
            // Device has emulated storage; external storage paths should have
            // userId burned into them.
            final String rawUserId;
            if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)
            {
                rawUserId = "";
            }
            else
            {
                final String path = Environment.getExternalStorageDirectory().getAbsolutePath();
                final String[] folders = DIR_SEPORATOR.split(path);
                final String lastFolder = folders[folders.length - 1];
                boolean isDigit = false;
                try
                {
                    Integer.valueOf(lastFolder);
                    isDigit = true;
                }
                catch(NumberFormatException ignored)
                {
                }
                rawUserId = isDigit ? lastFolder : "";
            }
            // /storage/emulated/0[1,2,...]
            if(TextUtils.isEmpty(rawUserId))
            {
                rv.add(rawEmulatedStorageTarget);
            }
            else
            {
                rv.add(rawEmulatedStorageTarget + File.separator + rawUserId);
            }
        }
        // Add all secondary storages
        if(!TextUtils.isEmpty(rawSecondaryStoragesStr))
        {
            // All Secondary SD-CARDs splited into array
            final String[] rawSecondaryStorages = rawSecondaryStoragesStr.split(File.pathSeparator);
            Collections.addAll(rv, rawSecondaryStorages);
        }
        return rv.toArray(new String[rv.size()]);
    }
    
    0 讨论(0)
  • 2020-11-22 05:42

    In order to retrieve all the External Storages (whether they are SD cards or internal non-removable storages), you can use the following code:

    final String state = Environment.getExternalStorageState();
    
    if ( Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state) ) {  // we can read the External Storage...           
        //Retrieve the primary External Storage:
        final File primaryExternalStorage = Environment.getExternalStorageDirectory();
    
        //Retrieve the External Storages root directory:
        final String externalStorageRootDir;
        if ( (externalStorageRootDir = primaryExternalStorage.getParent()) == null ) {  // no parent...
            Log.d(TAG, "External Storage: " + primaryExternalStorage + "\n");
        }
        else {
            final File externalStorageRoot = new File( externalStorageRootDir );
            final File[] files = externalStorageRoot.listFiles();
    
            for ( final File file : files ) {
                if ( file.isDirectory() && file.canRead() && (file.listFiles().length > 0) ) {  // it is a real directory (not a USB drive)...
                    Log.d(TAG, "External Storage: " + file.getAbsolutePath() + "\n");
                }
            }
        }
    }
    

    Alternatively, you might use System.getenv("EXTERNAL_STORAGE") to retrieve the primary External Storage directory (e.g. "/storage/sdcard0") and System.getenv("SECONDARY_STORAGE") to retieve the list of all the secondary directories (e.g. "/storage/extSdCard:/storage/UsbDriveA:/storage/UsbDriveB"). Remember that, also in this case, you might want to filter the list of secondary directories in order to exclude the USB drives.

    In any case, please note that using hard-coded paths is always a bad approach (expecially when every manufacturer may change it as pleased).

    0 讨论(0)
提交回复
热议问题