我正在开发一个Android应用程序来从外部SD卡读取视频文件以执行它们的某些功能。为了测试我的代码,我试图硬编码SD卡的路径,
文件档案=新档案(" /storage/632E-1AFA/Champion.mp4");
但现在我想让这个应用程序在多个设备上运行。所以我想要一种通用方法来获取外部SD卡路径。我尝试了 getExternalStorageDirectory 方法,但它指向手机的内部存储空间。 getExternalFilesDir 指向内部应用程序文件。
我还在 - 的帮助下尝试了 System.getenv()方法 - Android Open External Storage directory(sdcard) for storing file和Find an external SD card location但是当我尝试调试代码时它返回一个空路径。
我的应用包括外部存储的读写权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
我正在Android 6.0上测试我的应用,所以我也包含了运行时权限。如果有人可以帮我找到一种方法或方法来获得外置SD卡在多点移动设备上运行的路径,我将不胜感激。
答案 0 :(得分:1)
在下面找到一些有用的方法:
获取外部SD路径。 / * * @return外部SD路径 * /
public String getExternalSDPath() {
StorageVolume sv = new StorageHelper().getStorage(StorageVolume.Type.EXTERNAL);
if (sv != null) {
return sv.file.getPath();
} else {
String sdpath = System.getenv("SECONDARY_STORAGE");
if (sdpath == null || sdpath.isEmpty()) {
sdpath = "/storage/extSdCard";
}
return sdpath;
}
}
/ ** *获取内部SD路径。 * * @return内部SD路径 * /
public String getInternalSDPath() {
String sdpath = Environment.getExternalStorageDirectory().getPath();
return sdpath;
}
/ ** *提供外部SD。 * * @return true,如果成功的话 * /
public boolean externalSDAvailable() {
String path = getExternalSDPath();
if (path != null) {
File file = new File(path);
if (file != null && file.exists() && file.list() != null) {
return true && isExternalSDAvailable;
} else {
return false;
}
}
return false;
}
StorageHelper.java类:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.StringTokenizer;
import android.os.Environment;
// TODO: Auto-generated Javadoc
/**
* The Class StorageHelper.
*/
public final class StorageHelper {
// private static final String TAG = "StorageHelper";
/**
* Instantiates a new storage helper.
*/
public StorageHelper() {
}
/** The Constant STORAGES_ROOT. */
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;
}
}
/** The Constant AVOIDED_DEVICES. */
private static final String[] AVOIDED_DEVICES = new String[] { "rootfs", "tmpfs", "dvpts", "proc", "sysfs",
"none" };
/** The Constant AVOIDED_DIRECTORIES. */
private static final String[] AVOIDED_DIRECTORIES = new String[] { "obb", "asec" };
/** The Constant DISALLOWED_FILESYSTEMS. */
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 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;
}
/**
* Gets the storage.
*
* @param type the type
* @return the storage
*/
public StorageVolume getStorage(StorageVolume.Type type) {
List<StorageVolume> list_second = getStorages(false);
for (Iterator<StorageVolume> iterator = list_second.iterator(); iterator.hasNext();) {
StorageVolume storageVolume = (StorageVolume) iterator.next();
if (storageVolume.mType == type) {
boolean e = storageVolume.file != null && storageVolume.file.exists()
&& storageVolume.file.list() != null;
if (e) {
return storageVolume;
}
}
}
return null;
}
/**
* 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 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 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 <T> the generic type
* @param array Array to check
* @param object Object to find
* @return true, if the given array contains the object
*/
private <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 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 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;
/**
* Instantiates a new storage volume.
*
* @param device the device
* @param file the file
* @param fileSystem the file system
*/
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;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@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.
*
* @param obj the obj
* @return true, if successful
* @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);
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return file.getAbsolutePath() + (mReadOnly ? " ro " : " rw ") + mType + (mRemovable ? " R " : "")
+ (mEmulated ? " E " : "") + fileSystem;
}
}
}
答案 1 :(得分:-1)
此路径直接进入您的应用目录:
public String getPathToAppFolder(){
return Environment.getExternalStorageDirectory() + "/Android/data/" + context.getPackageName() + "/Files/";
}