- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在开发一个Android应用程序来从外部SD卡读取视频文件以对其执行某些功能。为了测试我的代码,我尝试对 SD 卡的路径进行硬编码,例如,
File file = new File("/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 卡的路径能够在多个移动设备上运行,我将不胜感激。
最佳答案
在下面找到一些有用的方法:
获取外部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;
}
}
}
关于java - android 4.0+版本读取文件的外部SD卡路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39083621/
无法使用 Hive 版本 1.1.0 HBase 版本 0.94.8 和 hadoop 版本 2.7.0 从 hive 创建 Hbase 表 hive (default)> CREATE TABLE
我试图为 electron app 创建可执行文件但面临这个问题 Unable to determine Electron version. Please specify an Electron ve
我正在尝试让自适应阈值在 python 绑定(bind)到 opencv 中工作(swig 一个 - 无法让 opencv 2.0 工作,因为我正在使用 beagleboard 因为交叉编译还没有工作
我一直在 linux 机器上使用 JMeter,在命令行下使用了一段时间。工作正常。 今天,我在 Windows 机器(新客户端等)上尝试了它,它确实可以工作,但在控制台窗口中输出有很大不同。 Lin
在我的编码环境中,我通常使用最新版本的 Java 和 Eclipse。当我编写源代码时,我不会注意我使用的 API 方法或类是否向后兼容旧版本的 Java 或 Eclipse。在 javadoc 中存
问题是关于版本的特定组合,但更普遍。 我刚刚从 Kubuntu 12.04 升级到 14.04。现在,当我想编译 CUDA 代码(使用 CUDA 6.5)时,我得到: #error -- unsupp
我目前正在对我的一些应用程序进行沙箱处理,看来我必须删除一些功能才能满足 Mac App Store 沙箱(和其他)规则。 显然用户不会因为失去功能而感到高兴,我担心他们不会指责苹果制定了愚蠢的规则,
我用 flash 和 js 版本创建了一个动画横幅。 是否可以检测低于版本 9 的 ie 版本,然后提供 Flash 横幅,否则提供 js 横幅。 最佳答案 您可以使用条件注释来检测 IE 版本
我有一个处理不同位置的数据库的应用程序,我想检查这些数据库是否使用 Firebird 2.5 或更高版本打开。我们最近从 Firebird 2.0 迁移到了 2.5,我们有很多数据库可以响应 sele
我正在开发一个应用程序,我使用托管在我的服务器上的 Java 和 Jersey 构建了后端部分。我在服务器上使用 Tomcat7 来调用 Web 服务。 我以前有一台安装了 Ubuntu 的计算机,我
我可以使用 GetVersionEx() 函数来获取 Windows 版本,但是这个函数将返回一个数字而不是一个字符串。但是没有问题,因为我可以将数字转换为字符串,例如: if (osvi.dwMaj
我已经在我的系统中安装了 Anaconda 2 & 3。 Anaconda 2 包含 python 2.7 & Anaconda 3 包含 python 3.6。 我需要使用命令提示符运行我的 pyt
我正在尝试构建一个 Android 项目,但发生了以下错误 Error:(10, 1) A problem occurred evaluating project ':app'. > Failed t
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 4 年前。 Improve this qu
在降级我的 GCC 之前,我想知道是否有办法确定我的机器中的哪些程序/框架或依赖项会中断,以及是否有更好的方法来执行 openpose 安装? (例如,在 CMake 中更改某些内容) 有没有办法在不
我已经在终端的代码sudo apt-get install Shadowsocks-qt5中安装了Shadowsocks-Qt5,然后我可以通过搜索找到启动图标,但是它当我点击图标时打不开。然后我尝试
在网络上找到的文档说,MLLP V2(第 2 版)是用于传输 HL7 版本 3 内容的所有消息传输协议(protocol)的要求。似乎 MLLP 第 2 版主要用于 HL7 第 3 版。 我们可以/应
我正在使用带有 selinium webdriver 的 Protractor 。我的chromeDriver版本是78.0.1,chrome版本是78.0.3904.97。两个版本都匹配,应该不会有
我正在按照教程设置 mysql 数据库并做一些事情。我无法找到数据库资源管理器。我读了很多,但在 Window->show View-> Dataxxx 或右侧上部选项卡中无法正常工作。 最佳答案 从
我已经在 KDE 桌面上安装了 Anaconda 2.0.1。当我运行 python 并看到所有已安装的模块时,我收到此消息“无法将不兼容的 Qt 库(版本 0x40801)与该库(版本 0x4080
我是一名优秀的程序员,十分优秀!