在API中,“内部存储”被称为“外部存储”。如
Environment文档中所述:
注意:这里的“external”一词可能会让您感到困惑。最好将此目录视为媒体/共享存储。它是一个可以容纳相对大量数据并且在所有应用程序之间共享(不强制执行权限)的文件系统。传统上,这是SD卡,但它也可以作为单独于受保护的内部存储器不同的设备中的内置存储器实现,并且可以在计算机上作为文件系统挂载。
要区分“Environment.getExternalStorageDirectory()”实际返回的是物理上的内部还是外部存储,请调用Environment.isExternalStorageEmulated()。如果它是模拟的,则为内部存储。在具有内部存储和sdcard插槽的较新设备上,Environment.getExternalStorageDirectory()将始终返回内部存储。而在仅具有sdcard作为媒体存储选项的旧设备上,它将始终返回sdcard。
使用当前Android API无法检索所有存储。
我已经创建了一个基于Vitaliy Polchuk答案中的方法的帮助器。
如何获取Android设备的已安装外部存储列表
注意:从KitKat开始,次要存储仅作为只读存储器可访问,您可能需要使用以下方法检查可写性。
public static boolean isReadOnly(@NonNull final StorageVolume volume) {
if (volume.mFile.equals(Environment.getExternalStorageDirectory())) {
return android.os.Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED_READ_ONLY);
} else {
if (volume.getType() == Type.USB) {
return volume.isReadOnly();
}
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 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"
};
public static List<StorageVolume> getStorages(final boolean includeUsb) {
final Map<String, List<StorageVolume>> deviceVolumeMap = new HashMap<String, List<StorageVolume>>();
if (!STORAGES_ROOT.equals(File.separator)) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("/proc/mounts"));
String line;
while ((line = reader.readLine()) != null) {
final StringTokenizer tokens = new StringTokenizer(line, " ");
final String device = tokens.nextToken();
if (arrayContains(AVOIDED_DEVICES, device)) {
continue;
}
final String path = tokens.nextToken();
if (!path.startsWith(STORAGES_ROOT)) {
continue;
}
if (pathContainsDir(path, AVOIDED_DIRECTORIES)) {
continue;
}
final String fileSystem = tokens.nextToken();
if (arrayContains(DISALLOWED_FILESYSTEMS, fileSystem)) {
continue;
}
final File file = new File(path);
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) {
}
}
}
}
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) {
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;
setTypeAndAdd(volumeList, v, includeUsb, true);
break;
}
if (i == volumesLength - 1) {
setTypeAndAdd(volumeList, v, includeUsb, false);
}
}
}
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;
}
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);
}
}
}
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;
}
}
private static <T> boolean arrayContains(T[] array, T object) {
for (final T item : array) {
if (item.equals(object)) {
return true;
}
}
return false;
}
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;
}
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;
}
public static final class StorageVolume {
public enum Type {
INTERNAL,
EXTERNAL,
USB
}
public final String device;
public final File file;
public final String fileSystem;
private boolean mReadOnly;
private boolean mRemovable;
private boolean mEmulated;
private Type mType;
StorageVolume(String device, File file, String fileSystem) {
this.device = device;
this.file = file;
this.fileSystem = fileSystem;
}
public Type getType() {
return mType;
}
public boolean isRemovable() {
return mRemovable;
}
public boolean isEmulated() {
return mEmulated;
}
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;
}
@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;
}
}
}
String root = Environment.getExternalStorageDirectory().toString();
如果您已经正确完成了所有操作,它将返回路径。请发布您的完整代码。 - Rethinavel