2014-03-06 175 views
26

我想打開外部存儲目錄路徑以便以編程方式保存文件。我試過但沒有獲取sdcard路徑。 我該如何做到這一點?有沒有解決方案?用於存儲文件的Android Open外部存儲目錄(sdcard)

private File path = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + ""); 

private File path = new File(Environment.getExternalStorageDirectory() + ""); 

我試圖從兩種方法獲得上述路徑但兩者都指向內部存儲器中。

當我們打開存儲器如果SD卡被peresent它會顯示像如下─ enter image description here

設備存儲& SD存儲卡。

我想通過編碼獲得sd內存路徑。 在manifest-

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
    <uses-permission android:name="android.permission.STORAGE" /> 
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 
+0

是的,我已經給WRITE_EXTERNAL存儲許可 –

+0

另外添加READ_EXTERNAL存儲許可 –

+0

@BlackTiger:仍然沒有得到SD卡路徑 –

回答

-1

我已經給權限嘗試使用

new File(Environment.getExternalStorageDirectory(),"somefilename");

而且不要忘了添加WRITE_EXTERNAL存儲和READ_EXTERNAL存儲權限

+0

This dpesnt work again KITKAT + –

4

希望這對您的工作:

File yourFile = new File(Environment.getExternalStorageDirectory(), "textarabics.txt"); 

這將要給你的SD卡路徑:

File path = Environment.getExternalStorageDirectory(); 

試試這個:

String pathName = "/mnt/"; 

或試試這個:

String pathName = "/storage/"; 
+2

它的設備依賴不同設備爲不同的設備 –

+0

爲什麼downVote ????? –

+0

我還沒有投票給你失望 –

16

內部存儲的API中被稱爲 「外部存儲」 。

由於Environment文檔

注中提到:不要被這個詞在這裏混淆「外部」。這個目錄可以更好地被認爲是媒體/共享存儲。它是一個文件系統,可以容納大量的數據並在所有應用程序之間共享(不強制執行權限)。傳統上這是一張SD卡,但它也可以實現爲與受保護的內部存儲器不同的設備中的內置存儲器,並且可以作爲文件系統安裝在計算機上。

要區分「Environment.getExternalStorageDirectory()」是否實際返回物理內部或外部存儲,請調用Environment.isExternalStorageEmulated()。如果它被仿效,那麼它就是內在的。在具有內部存儲和sdcard插槽的較新設備上,Environment.getExternalStorageDirectory()將始終返回內部存儲。而在只有sdcard作爲媒體存儲選項的舊設備上,它將始終返回sdcard。

無法使用當前Android API檢索所有存儲。

我已經創建了一個基於維塔利Polchuk在回答方法的輔助之下

How can I get the list of mounted external storage of android device

注意:開始奇巧二級存儲只能訪問爲只讀,你可能要檢查可寫性用以下方法

/** 
* Checks whether the StorageVolume is read-only 
* 
* @param volume 
*   StorageVolume to check 
* @return true, if volume is mounted read-only 
*/ 
public static boolean isReadOnly(@NonNull final StorageVolume volume) { 
    if (volume.mFile.equals(Environment.getExternalStorageDirectory())) { 
     // is a primary storage, check mounted state by Environment 
     return android.os.Environment.getExternalStorageState().equals(
       android.os.Environment.MEDIA_MOUNTED_READ_ONLY); 
    } else { 
     if (volume.getType() == Type.USB) { 
      return volume.isReadOnly(); 
     } 
     //is not a USB storagem so it's read-only if it's mounted read-only or if it's a KitKat device 
     return volume.isReadOnly() || Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; 
    } 
} 

StorageHelper類

import java.io.BufferedReader; 
import java.io.File; 
import java.io.FileNotFoundException; 
import java.io.FileReader; 
import java.io.IOException; 
import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 
import java.util.Map.Entry; 
import java.util.StringTokenizer; 

import android.os.Environment; 

public final class StorageHelper { 

    //private static final String TAG = "StorageHelper"; 

    private StorageHelper() { 
    } 

    private static final String STORAGES_ROOT; 

    static { 
     final String primaryStoragePath = Environment.getExternalStorageDirectory() 
       .getAbsolutePath(); 
     final int index = primaryStoragePath.indexOf(File.separatorChar, 1); 
     if (index != -1) { 
      STORAGES_ROOT = primaryStoragePath.substring(0, index + 1); 
     } else { 
      STORAGES_ROOT = File.separator; 
     } 
    } 

    private static final String[] AVOIDED_DEVICES = new String[] { 
     "rootfs", "tmpfs", "dvpts", "proc", "sysfs", "none" 
    }; 

    private static final String[] AVOIDED_DIRECTORIES = new String[] { 
     "obb", "asec" 
    }; 

    private static final String[] DISALLOWED_FILESYSTEMS = new String[] { 
     "tmpfs", "rootfs", "romfs", "devpts", "sysfs", "proc", "cgroup", "debugfs" 
    }; 

    /** 
    * Returns a list of mounted {@link StorageVolume}s Returned list always 
    * includes a {@link StorageVolume} for 
    * {@link Environment#getExternalStorageDirectory()} 
    * 
    * @param includeUsb 
    *   if true, will include USB storages 
    * @return list of mounted {@link StorageVolume}s 
    */ 
    public static List<StorageVolume> getStorages(final boolean includeUsb) { 
     final Map<String, List<StorageVolume>> deviceVolumeMap = new HashMap<String, List<StorageVolume>>(); 

     // this approach considers that all storages are mounted in the same non-root directory 
     if (!STORAGES_ROOT.equals(File.separator)) { 
      BufferedReader reader = null; 
      try { 
       reader = new BufferedReader(new FileReader("/proc/mounts")); 
       String line; 
       while ((line = reader.readLine()) != null) { 
        // Log.d(TAG, line); 
        final StringTokenizer tokens = new StringTokenizer(line, " "); 

        final String device = tokens.nextToken(); 
        // skipped devices that are not sdcard for sure 
        if (arrayContains(AVOIDED_DEVICES, device)) { 
         continue; 
        } 

        // should be mounted in the same directory to which 
        // the primary external storage was mounted 
        final String path = tokens.nextToken(); 
        if (!path.startsWith(STORAGES_ROOT)) { 
         continue; 
        } 

        // skip directories that indicate tha volume is not a storage volume 
        if (pathContainsDir(path, AVOIDED_DIRECTORIES)) { 
         continue; 
        } 

        final String fileSystem = tokens.nextToken(); 
        // don't add ones with non-supported filesystems 
        if (arrayContains(DISALLOWED_FILESYSTEMS, fileSystem)) { 
         continue; 
        } 

        final File file = new File(path); 
        // skip volumes that are not accessible 
        if (!file.canRead() || !file.canExecute()) { 
         continue; 
        } 

        List<StorageVolume> volumes = deviceVolumeMap.get(device); 
        if (volumes == null) { 
         volumes = new ArrayList<StorageVolume>(3); 
         deviceVolumeMap.put(device, volumes); 
        } 

        final StorageVolume volume = new StorageVolume(device, file, fileSystem); 
        final StringTokenizer flags = new StringTokenizer(tokens.nextToken(), ","); 
        while (flags.hasMoreTokens()) { 
         final String token = flags.nextToken(); 
         if (token.equals("rw")) { 
          volume.mReadOnly = false; 
          break; 
         } else if (token.equals("ro")) { 
          volume.mReadOnly = true; 
          break; 
         } 
        } 
        volumes.add(volume); 
       } 

      } catch (IOException ex) { 
       ex.printStackTrace(); 
      } finally { 
       if (reader != null) { 
        try { 
         reader.close(); 
        } catch (IOException ex) { 
         // ignored 
        } 
       } 
      } 
     } 

     // remove volumes that are the same devices 
     boolean primaryStorageIncluded = false; 
     final File externalStorage = Environment.getExternalStorageDirectory(); 
     final List<StorageVolume> volumeList = new ArrayList<StorageVolume>(); 
     for (final Entry<String, List<StorageVolume>> entry : deviceVolumeMap.entrySet()) { 
      final List<StorageVolume> volumes = entry.getValue(); 
      if (volumes.size() == 1) { 
       // go ahead and add 
       final StorageVolume v = volumes.get(0); 
       final boolean isPrimaryStorage = v.file.equals(externalStorage); 
       primaryStorageIncluded |= isPrimaryStorage; 
       setTypeAndAdd(volumeList, v, includeUsb, isPrimaryStorage); 
       continue; 
      } 
      final int volumesLength = volumes.size(); 
      for (int i = 0; i < volumesLength; i++) { 
       final StorageVolume v = volumes.get(i); 
       if (v.file.equals(externalStorage)) { 
        primaryStorageIncluded = true; 
        // add as external storage and continue 
        setTypeAndAdd(volumeList, v, includeUsb, true); 
        break; 
       } 
       // if that was the last one and it's not the default external 
       // storage then add it as is 
       if (i == volumesLength - 1) { 
        setTypeAndAdd(volumeList, v, includeUsb, false); 
       } 
      } 
     } 
     // add primary storage if it was not found 
     if (!primaryStorageIncluded) { 
      final StorageVolume defaultExternalStorage = new StorageVolume("", externalStorage, "UNKNOWN"); 
      defaultExternalStorage.mEmulated = Environment.isExternalStorageEmulated(); 
      defaultExternalStorage.mType = 
        defaultExternalStorage.mEmulated ? StorageVolume.Type.INTERNAL 
          : StorageVolume.Type.EXTERNAL; 
      defaultExternalStorage.mRemovable = Environment.isExternalStorageRemovable(); 
      defaultExternalStorage.mReadOnly = 
        Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY); 
      volumeList.add(0, defaultExternalStorage); 
     } 
     return volumeList; 
    } 

    /** 
    * Sets {@link StorageVolume.Type}, removable and emulated flags and adds to 
    * volumeList 
    * 
    * @param volumeList 
    *   List to add volume to 
    * @param v 
    *   volume to add to list 
    * @param includeUsb 
    *   if false, volume with type {@link StorageVolume.Type#USB} will 
    *   not be added 
    * @param asFirstItem 
    *   if true, adds the volume at the beginning of the volumeList 
    */ 
    private static void setTypeAndAdd(final List<StorageVolume> volumeList, 
      final StorageVolume v, 
      final boolean includeUsb, 
      final boolean asFirstItem) { 
     final StorageVolume.Type type = resolveType(v); 
     if (includeUsb || type != StorageVolume.Type.USB) { 
      v.mType = type; 
      if (v.file.equals(Environment.getExternalStorageDirectory())) { 
       v.mRemovable = Environment.isExternalStorageRemovable(); 
      } else { 
       v.mRemovable = type != StorageVolume.Type.INTERNAL; 
      } 
      v.mEmulated = type == StorageVolume.Type.INTERNAL; 
      if (asFirstItem) { 
       volumeList.add(0, v); 
      } else { 
       volumeList.add(v); 
      } 
     } 
    } 

    /** 
    * Resolved {@link StorageVolume} type 
    * 
    * @param v 
    *   {@link StorageVolume} to resolve type for 
    * @return {@link StorageVolume} type 
    */ 
    private static StorageVolume.Type resolveType(final StorageVolume v) { 
     if (v.file.equals(Environment.getExternalStorageDirectory()) 
       && Environment.isExternalStorageEmulated()) { 
      return StorageVolume.Type.INTERNAL; 
     } else if (containsIgnoreCase(v.file.getAbsolutePath(), "usb")) { 
      return StorageVolume.Type.USB; 
     } else { 
      return StorageVolume.Type.EXTERNAL; 
     } 
    } 

    /** 
    * Checks whether the array contains object 
    * 
    * @param array 
    *   Array to check 
    * @param object 
    *   Object to find 
    * @return true, if the given array contains the object 
    */ 
    private static <T> boolean arrayContains(T[] array, T object) { 
     for (final T item : array) { 
      if (item.equals(object)) { 
       return true; 
      } 
     } 
     return false; 
    } 

    /** 
    * Checks whether the path contains one of the directories 
    * 
    * For example, if path is /one/two, it returns true input is "one" or 
    * "two". Will return false if the input is one of "one/two", "/one" or 
    * "/two" 
    * 
    * @param path 
    *   path to check for a directory 
    * @param dirs 
    *   directories to find 
    * @return true, if the path contains one of the directories 
    */ 
    private static boolean pathContainsDir(final String path, final String[] dirs) { 
     final StringTokenizer tokens = new StringTokenizer(path, File.separator); 
     while (tokens.hasMoreElements()) { 
      final String next = tokens.nextToken(); 
      for (final String dir : dirs) { 
       if (next.equals(dir)) { 
        return true; 
       } 
      } 
     } 
     return false; 
    } 

    /** 
    * Checks ifString contains a search String irrespective of case, handling. 
    * Case-insensitivity is defined as by 
    * {@link String#equalsIgnoreCase(String)}. 
    * 
    * @param str 
    *   the String to check, may be null 
    * @param searchStr 
    *   the String to find, may be null 
    * @return true if the String contains the search String irrespective of 
    *   case or false if not or {@code null} string input 
    */ 
    public static boolean containsIgnoreCase(final String str, final String searchStr) { 
     if (str == null || searchStr == null) { 
      return false; 
     } 
     final int len = searchStr.length(); 
     final int max = str.length() - len; 
     for (int i = 0; i <= max; i++) { 
      if (str.regionMatches(true, i, searchStr, 0, len)) { 
       return true; 
      } 
     } 
     return false; 
    } 

    /** 
    * Represents storage volume information 
    */ 
    public static final class StorageVolume { 

     /** 
     * Represents {@link StorageVolume} type 
     */ 
     public enum Type { 
      /** 
      * Device built-in internal storage. Probably points to 
      * {@link Environment#getExternalStorageDirectory()} 
      */ 
      INTERNAL, 

      /** 
      * External storage. Probably removable, if no other 
      * {@link StorageVolume} of type {@link #INTERNAL} is returned by 
      * {@link StorageHelper#getStorages(boolean)}, this might be 
      * pointing to {@link Environment#getExternalStorageDirectory()} 
      */ 
      EXTERNAL, 

      /** 
      * Removable usb storage 
      */ 
      USB 
     } 

     /** 
     * Device name 
     */ 
     public final String device; 

     /** 
     * Points to mount point of this device 
     */ 
     public final File file; 

     /** 
     * File system of this device 
     */ 
     public final String fileSystem; 

     /** 
     * if true, the storage is mounted as read-only 
     */ 
     private boolean mReadOnly; 

     /** 
     * If true, the storage is removable 
     */ 
     private boolean mRemovable; 

     /** 
     * If true, the storage is emulated 
     */ 
     private boolean mEmulated; 

     /** 
     * Type of this storage 
     */ 
     private Type mType; 

     StorageVolume(String device, File file, String fileSystem) { 
      this.device = device; 
      this.file = file; 
      this.fileSystem = fileSystem; 
     } 

     /** 
     * Returns type of this storage 
     * 
     * @return Type of this storage 
     */ 
     public Type getType() { 
      return mType; 
     } 

     /** 
     * Returns true if this storage is removable 
     * 
     * @return true if this storage is removable 
     */ 
     public boolean isRemovable() { 
      return mRemovable; 
     } 

     /** 
     * Returns true if this storage is emulated 
     * 
     * @return true if this storage is emulated 
     */ 
     public boolean isEmulated() { 
      return mEmulated; 
     } 

     /** 
     * Returns true if this storage is mounted as read-only 
     * 
     * @return true if this storage is mounted as read-only 
     */ 
     public boolean isReadOnly() { 
      return mReadOnly; 
     } 

     @Override 
     public int hashCode() { 
      final int prime = 31; 
      int result = 1; 
      result = prime * result + ((file == null) ? 0 : file.hashCode()); 
      return result; 
     } 

     /** 
     * Returns true if the other object is StorageHelper and it's 
     * {@link #file} matches this one's 
     * 
     * @see Object#equals(Object) 
     */ 
     @Override 
     public boolean equals(Object obj) { 
      if (obj == this) { 
       return true; 
      } 
      if (obj == null) { 
       return false; 
      } 
      if (getClass() != obj.getClass()) { 
       return false; 
      } 
      final StorageVolume other = (StorageVolume) obj; 
      if (file == null) { 
       return other.file == null; 
      } 
      return file.equals(other.file); 
     } 

     @Override 
     public String toString() { 
      return file.getAbsolutePath() + (mReadOnly ? " ro " : " rw ") + mType + (mRemovable ? " R " : "") 
        + (mEmulated ? " E " : "") + fileSystem; 
     } 
    } 
} 
+0

其返回null –

+0

如果您刪除StringUtils.containsIgnoreCase()並返回第一個發現的讀寫執行一個,它仍然返回null? –

+0

如果我刪除,如果條件返回設備目錄路徑 –

55

我一直有完全相同的問題!

爲了獲得內部SD卡就可以使用

String extStore = System.getenv("EXTERNAL_STORAGE"); 
File f_exts = new File(extStore); 

要獲得外部SD卡就可以使用

String secStore = System.getenv("SECONDARY_STORAGE"); 
File f_secs = new File(secStore); 

在運行代碼

extStore = "/storage/emulated/legacy" 
secStore = "/storage/extSdCarcd" 

作品完美!

+0

這是很好的區分主外部和外部輔助存儲也..謝謝... –

+0

感謝您的答案。我加了一個補充,但它不適合這裏的評論。將我的答案設置爲原始答案。 – Alexandre

+0

最後一個有效的答案。非常感謝! – Prexx

3

補充rijul古普塔答案:

String strSDCardPath = System.getenv("SECONDARY_STORAGE"); 

    if ((strSDCardPath == null) || (strSDCardPath.length() == 0)) { 
     strSDCardPath = System.getenv("EXTERNAL_SDCARD_STORAGE"); 
    } 

    //If may get a full path that is not the right one, even if we don't have the SD Card there. 
    //We just need the "/mnt/extSdCard/" i.e and check if it's writable 
    if(strSDCardPath != null) { 
     if (strSDCardPath.contains(":")) { 
      strSDCardPath = strSDCardPath.substring(0, strSDCardPath.indexOf(":")); 
     } 
     File externalFilePath = new File(strSDCardPath); 

     if (externalFilePath.exists() && externalFilePath.canWrite()){ 
      //do what you need here 
     } 
    } 
0

我想開外部存儲的目錄路徑保存文件的 programatically.I試過,但沒有得到SD卡路徑。我該怎麼做 這個?有沒有解決方案?

要保存您的應用程序文件的SD卡,你應該Context使用File[] getExternalFilesDirs (String type)方法。通常,第二個返回的路徑將是microSD卡的存儲路徑(如果有的話)。

在我的手機上,返回的第二條路徑是/storage/sdcard1/Android/data/your.application.package.appname/files,通過null作爲getExternalFilesDirs (String type)的參數。但路徑可能會因不同手機而有所不同,不同的Android版本。

File getExternalStorageDirectory()File getExternalStoragePublicDirectory (String type)Environment類可能會返回SD卡目錄或內部存儲器目錄,具體取決於您的手機型號和Android操作系統版本。

因爲根據Official Android Guide外部存儲器可以是

可移動存儲介質(例如,SD卡)或內部 (不可移動)的存儲。

根據谷歌/ Android官方文檔的內部和外部存儲術語從我們所想的完全不同

0

採取@ rijul的回答着,它不棉花糖及以上版本的工作:

 //for pre-marshmallow versions 
     String path = System.getenv("SECONDARY_STORAGE"); 

     // For Marshmallow, use getExternalCacheDirs() instead of System.getenv("SECONDARY_STORAGE") 
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
      File[] externalCacheDirs = mContext.getExternalCacheDirs(); 
      for (File file : externalCacheDirs) { 
       if (Environment.isExternalStorageRemovable(file)) { 
        // Path is in format /storage.../Android.... 
        // Get everything before /Android 
        path = file.getPath().split("/Android")[0]; 
        break; 
       } 
      } 
     } 


     // Android avd emulator doesn't support this variable name so using other one 
     if ((null == path) || (path.length() == 0)) 
      path = Environment.getExternalStorageDirectory().getAbsolutePath(); 
相關問題