Android打开外部存储目录(SD卡)存储文件

我想要打开外部存储目录path来保存文件programatically.I尝试,但没有得到SD卡path。 我怎么能做到这一点?有没有解决scheme?

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

要么

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

我试图从两种方法获得path,但都指向内部记忆。

当我们打开存储内存,如果SD卡是peresent它将显示如下 – 在这里输入图像描述

设备存储和SD存储卡。

我想通过编码获得sd内存path。 我已经在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" /> 

我一直有完全相同的问题!

要获得可以使用的内部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" 

完美的作品!

内部存储在API中被称为“外部存储”。

如环境文档中所述

注意:这里不要被“外部”这个词混淆。 这个目录可以更好地被认为是媒体/共享存储。 这是一个文件系统,可以容纳大量的数据,并在所有应用程序之间共享(不强制执行权限)。 传统上,这是一个SD卡,但它也可以实现为与受保护的内部存储器不同的设备中的内置存储器,并且可以作为文件系统安装在计算机上。

要区分“Environment.getExternalStorageDirectory()”是否实际返回物理内部或外部存储,请调用Environment.isExternalStorageEmulated()。 如果是模仿,那就是内在。 在具有内部存储和sdcard插槽的较新设备上,Environment.getExternalStorageDirectory()将始终返回内部存储。 而在只有SD卡作为媒体存储选项的旧设备上,它将始终返回SD卡。

使用当前的Android API无法检索所有存储。

我在下面的答案中创build了一个基于Vitaliy Polchuk方法的帮手

我怎样才能得到安装Android设备的外部存储列表

注:启动KitKat二级存储只能以READ-ONLY方式访问 ,您可能需要使用以下方法检查可写性

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

希望它为你工作:

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

这将给你的SD卡path:

 File path = Environment.getExternalStorageDirectory(); 

尝试这个:

 String pathName = "/mnt/"; 

或者试试这个:

 String pathName = "/storage/"; 

补充rijul gupta答案:

 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/" ie 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 } } 

拿@ 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(); 

我想要打开外部存储目录path来保存文件programatically.I尝试,但没有得到SD卡path。 我怎样才能做到这一点?有没有解决scheme?

要将应用程序文件存储在SD卡中, Context类中使用File[] getExternalFilesDirs (String type)方法。 通常,第二个返回的path将是microSD卡的存储path(如果有的话)。

在我的手机上,返回的第二个path是在将null作为parameter passing给getExternalFilesDirs (String type)之后的/storage/sdcard1/Android/data/your.application.package.appname/files 。 但path可能会因不同的手机而有所不同,不同的Android版本

Environment类中的File getExternalStorageDirectory ()File getExternalStoragePublicDirectory (String type)可能会根据您的手机型号和Android操作系统版本返回SD卡目录或内部内存目录。

因为根据官方的Android指南外部存储可以

可移动存储介质(如SD卡)或内部(不可移动)存储。

根据Google /官方Android文档的内部和外部存储术语与我们所认为的完全不同

尝试使用

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

不要忘记添加WRITE_EXTERNAL STORAGE和READ_EXTERNAL STORAGE权限