- 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/
我正在编写一个具有以下签名的 Java 方法。 void Logger(Method method, Object[] args); 如果一个方法(例如 ABC() )调用此方法 Logger,它应该
我是 Java 新手。 我的问题是我的 Java 程序找不到我试图用作的图像文件一个 JButton。 (目前这段代码什么也没做,因为我只是得到了想要的外观第一的)。这是我的主课 代码: packag
好的,今天我在接受采访,我已经编写 Java 代码多年了。采访中说“Java 垃圾收集是一个棘手的问题,我有几个 friend 一直在努力弄清楚。你在这方面做得怎么样?”。她是想骗我吗?还是我的一生都
我的 friend 给了我一个谜语让我解开。它是这样的: There are 100 people. Each one of them, in his turn, does the following
如果我将使用 Java 5 代码的应用程序编译成字节码,生成的 .class 文件是否能够在 Java 1.4 下运行? 如果后者可以工作并且我正在尝试在我的 Java 1.4 应用程序中使用 Jav
有关于why Java doesn't support unsigned types的问题以及一些关于处理无符号类型的问题。我做了一些搜索,似乎 Scala 也不支持无符号数据类型。限制是Java和S
我只是想知道在一个 java 版本中生成的字节码是否可以在其他 java 版本上运行 最佳答案 通常,字节码无需修改即可在 较新 版本的 Java 上运行。它不会在旧版本上运行,除非您使用特殊参数 (
我有一个关于在命令提示符下执行 java 程序的基本问题。 在某些机器上我们需要指定 -cp 。 (类路径)同时执行java程序 (test为java文件名与.class文件存在于同一目录下) jav
我已经阅读 StackOverflow 有一段时间了,现在我才鼓起勇气提出问题。我今年 20 岁,目前在我的家乡(罗马尼亚克卢日-纳波卡)就读 IT 大学。足以介绍:D。 基本上,我有一家提供簿记应用
我有 public JSONObject parseXML(String xml) { JSONObject jsonObject = XML.toJSONObject(xml); r
我已经在 Java 中实现了带有动态类型的简单解释语言。不幸的是我遇到了以下问题。测试时如下代码: def main() { def ks = Map[[1, 2]].keySet()
一直提示输入 1 到 10 的数字 - 结果应将 st、rd、th 和 nd 添加到数字中。编写一个程序,提示用户输入 1 到 10 之间的任意整数,然后以序数形式显示该整数并附加后缀。 public
我有这个 DownloadFile.java 并按预期下载该文件: import java.io.*; import java.net.URL; public class DownloadFile {
我想在 GUI 上添加延迟。我放置了 2 个 for 循环,然后重新绘制了一个标签,但这 2 个 for 循环一个接一个地执行,并且标签被重新绘制到最后一个。 我能做什么? for(int i=0;
我正在对对象 Student 的列表项进行一些测试,但是我更喜欢在 java 类对象中创建硬编码列表,然后从那里提取数据,而不是连接到数据库并在结果集中选择记录。然而,自从我这样做以来已经很长时间了,
我知道对象创建分为三个部分: 声明 实例化 初始化 classA{} classB extends classA{} classA obj = new classB(1,1); 实例化 它必须使用
我有兴趣使用 GPRS 构建车辆跟踪系统。但是,我有一些问题要问以前做过此操作的人: GPRS 是最好的技术吗?人们意识到任何问题吗? 我计划使用 Java/Java EE - 有更好的技术吗? 如果
我可以通过递归方法反转数组,例如:数组={1,2,3,4,5} 数组结果={5,4,3,2,1}但我的结果是相同的数组,我不知道为什么,请帮助我。 public class Recursion { p
有这样的标准方式吗? 包括 Java源代码-测试代码- Ant 或 Maven联合单元持续集成(可能是巡航控制)ClearCase 版本控制工具部署到应用服务器 最后我希望有一个自动构建和集成环境。
我什至不知道这是否可能,我非常怀疑它是否可能,但如果可以,您能告诉我怎么做吗?我只是想知道如何从打印机打印一些文本。 有什么想法吗? 最佳答案 这里有更简单的事情。 import javax.swin
我是一名优秀的程序员,十分优秀!