三星 Galaxy S3具有外部SD卡插槽,它被挂载到 /mnt/extSdCard
。
我该如何像Environment.getExternalStorageDirectory()
这样获取此路径?
这将返回mnt/sdcard
,我找不到用于外部SD卡的API。(或某些平板电脑上的可移动USB存储器。)
三星 Galaxy S3具有外部SD卡插槽,它被挂载到 /mnt/extSdCard
。
我该如何像Environment.getExternalStorageDirectory()
这样获取此路径?
这将返回mnt/sdcard
,我找不到用于外部SD卡的API。(或某些平板电脑上的可移动USB存储器。)
以下解决方案是根据其他回答组合而成的(如@ono所提到的),它处理了在Marshmallow版本中System.getenv("SECONDARY_STORAGE")
无用的事实。
已测试并可行于:
Samsung Galaxy Tab A (Android 6.0.1 - Stock)
/**
* Returns all available external SD-Card roots in the system.
*
* @return paths to all available external SD-Card roots in the system.
*/
public static String[] getStorageDirectories() {
String [] storageDirectories;
String rawSecondaryStoragesStr = System.getenv("SECONDARY_STORAGE");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
List<String> results = new ArrayList<String>();
File[] externalDirs = applicationContext.getExternalFilesDirs(null);
for (File file : externalDirs) {
String path = file.getPath().split("/Android")[0];
if((Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Environment.isExternalStorageRemovable(file))
|| rawSecondaryStoragesStr != null && rawSecondaryStoragesStr.contains(path)){
results.add(path);
}
}
storageDirectories = results.toArray(new String[0]);
}else{
final Set<String> rv = new HashSet<String>();
if (!TextUtils.isEmpty(rawSecondaryStoragesStr)) {
final String[] rawSecondaryStorages = rawSecondaryStoragesStr.split(File.pathSeparator);
Collections.addAll(rv, rawSecondaryStorages);
}
storageDirectories = rv.toArray(new String[rv.size()]);
}
return storageDirectories;
}
rawSecondaryStoragesStr.contains(path)
可以允许内部存储也被添加;我们最好删除该条件。我遇到了这个问题,因为我的设备使用System.getenv("SECONDARY_STORAGE")
返回内部存储目录,但在KitKat上使用System.getenv(EXTERNAL_STORAGE)
返回外部存储卡路径;看起来不同的供应商实现方式不同,没有任何标准。 - Gokul NCextSdCard
,而在其他设备中,则显示为sdcard1
。String sdpath,sd1path,usbdiskpath,sd0path;
if(new File("/storage/extSdCard/").exists())
{
sdpath="/storage/extSdCard/";
Log.i("Sd Cardext Path",sdpath);
}
if(new File("/storage/sdcard1/").exists())
{
sd1path="/storage/sdcard1/";
Log.i("Sd Card1 Path",sd1path);
}
if(new File("/storage/usbcard1/").exists())
{
usbdiskpath="/storage/usbcard1/";
Log.i("USB Path",usbdiskpath);
}
if(new File("/storage/sdcard0/").exists())
{
sd0path="/storage/sdcard0/";
Log.i("Sd Card0 Path",sd0path);
}
是的。不同的制造商使用不同的SD卡名称,例如在三星Tab 3中使用extsd,在其他三星设备中使用sdcard,不同的制造商使用不同的名称。
我有和你一样的需求,所以我从我的项目中创建了一个示例供你参考,可以前往此链接Android目录选择器示例,该示例使用了andriod-dirchooser库。这个示例可以检测SD卡并列出所有子文件夹,并且还可以检测设备是否有多个SD卡。
代码的部分内容如下,完整示例请前往此链接Android目录选择器
/**
* Returns the path to internal storage ex:- /storage/emulated/0
*
* @return
*/
private String getInternalDirectoryPath() {
return Environment.getExternalStorageDirectory().getAbsolutePath();
}
/**
* Returns the SDcard storage path for samsung ex:- /storage/extSdCard
*
* @return
*/
private String getSDcardDirectoryPath() {
return System.getenv("SECONDARY_STORAGE");
}
mSdcardLayout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
String sdCardPath;
/***
* Null check because user may click on already selected buton before selecting the folder
* And mSelectedDir may contain some wrong path like when user confirm dialog and swith back again
*/
if (mSelectedDir != null && !mSelectedDir.getAbsolutePath().contains(System.getenv("SECONDARY_STORAGE"))) {
mCurrentInternalPath = mSelectedDir.getAbsolutePath();
} else {
mCurrentInternalPath = getInternalDirectoryPath();
}
if (mCurrentSDcardPath != null) {
sdCardPath = mCurrentSDcardPath;
} else {
sdCardPath = getSDcardDirectoryPath();
}
//When there is only one SDcard
if (sdCardPath != null) {
if (!sdCardPath.contains(":")) {
updateButtonColor(STORAGE_EXTERNAL);
File dir = new File(sdCardPath);
changeDirectory(dir);
} else if (sdCardPath.contains(":")) {
//Multiple Sdcards show root folder and remove the Internal storage from that.
updateButtonColor(STORAGE_EXTERNAL);
File dir = new File("/storage");
changeDirectory(dir);
}
} else {
//In some unknown scenario at least we can list the root folder
updateButtonColor(STORAGE_EXTERNAL);
File dir = new File("/storage");
changeDirectory(dir);
}
}
});
System.getenv("SECONDARY_STORAGE")
在Marshmallow中返回null。这是另一种查找所有外部目录的方法。您可以检查它是否可移动,以确定是内部还是外部。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
File[] externalCacheDirs = context.getExternalCacheDirs();
for (File file : externalCacheDirs) {
if (Environment.isExternalStorageRemovable(file)) {
// It's a removable storage
}
}
}
File[] files = null;
File file = new File("/storage");// /storage/emulated
if (file.exists()) {
files = file.listFiles();
}
if (null != files)
for (int j = 0; j < files.length; j++) {
Log.e(TAG, "" + files[j]);
Log.e(TAG, "//--//--// " + files[j].exists());
if (files[j].toString().replaceAll("_", "")
.toLowerCase().contains("extsdcard")) {
external_path = files[j].toString();
break;
} else if (files[j].toString().replaceAll("_", "")
.toLowerCase()
.contains("sdcard".concat(Integer.toString(j)))) {
// external_path = files[j].toString();
}
Log.e(TAG, "--///--///-- " + external_path);
}
static String getExternalStorage(){
String exts = Environment.getExternalStorageDirectory().getPath();
try {
FileReader fr = new FileReader(new File("/proc/mounts"));
BufferedReader br = new BufferedReader(fr);
String sdCard=null;
String line;
while((line = br.readLine())!=null){
if(line.contains("secure") || line.contains("asec")) continue;
if(line.contains("fat")){
String[] pars = line.split("\\s");
if(pars.length<2) continue;
if(pars[1].equals(exts)) continue;
sdCard =pars[1];
break;
}
}
fr.close();
br.close();
return sdCard;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
String path = Environment.getExternalStorageDirectory()
+ File.separator + Environment.DIRECTORY_PICTURES;
File dir = new File(path);
我已经尝试了Dmitriy Lozenko和Gnathonic提供的解决方案,但都没有帮助我检索到外部SD卡目录的路径。mount
命令执行包含所需的外部SD卡目录路径(即/Storage/A5F9-15F4),但它与正则表达式不匹配,因此未返回。我不理解三星遵循的目录命名机制。为什么他们偏离标准(即extsdcard),并像在我的情况下一样提出一些非常奇怪的东西(即/Storage/A5F9-15F4)。我是否遗漏了什么?无论如何,更改Gnathonic解决方案的正则表达式后,我成功获取了有效的SD卡目录:
final HashSet<String> out = new HashSet<String>();
String reg = "(?i).*(vold|media_rw).*(sdcard|vfat|ntfs|exfat|fat32|ext3|ext4).*rw.*";
String s = "";
try {
final Process process = new ProcessBuilder().command("mount")
.redirectErrorStream(true).start();
process.waitFor();
final InputStream is = process.getInputStream();
final byte[] buffer = new byte[1024];
while (is.read(buffer) != -1) {
s = s + new String(buffer);
}
is.close();
} catch (final Exception e) {
e.printStackTrace();
}
// parse output
final String[] lines = s.split("\n");
for (String line : lines) {
if (!line.toLowerCase(Locale.US).contains("asec")) {
if (line.matches(reg)) {
String[] parts = line.split(" ");
for (String part : parts) {
if (part.startsWith("/"))
if (!part.toLowerCase(Locale.US).contains("vold"))
out.add(part);
}
}
}
}
return out;
我不确定这是否是一个有效的解决方案,以及它是否适用于其他三星平板电脑,但它暂时解决了我的问题。以下是在Android(v6.0)中检索可移动SD卡路径的另一种方法。我已经在Android Marshmallow上测试了该方法,并且它可以正常工作。其中使用的方法非常基本,肯定也适用于其他版本,但测试是必要的。对此有一些了解将会很有帮助:
public static String getSDCardDirPathForAndroidMarshmallow() {
File rootDir = null;
try {
// Getting external storage directory file
File innerDir = Environment.getExternalStorageDirectory();
// Temporarily saving retrieved external storage directory as root
// directory
rootDir = innerDir;
// Splitting path for external storage directory to get its root
// directory
String externalStorageDirPath = innerDir.getAbsolutePath();
if (externalStorageDirPath != null
&& externalStorageDirPath.length() > 1
&& externalStorageDirPath.startsWith("/")) {
externalStorageDirPath = externalStorageDirPath.substring(1,
externalStorageDirPath.length());
}
if (externalStorageDirPath != null
&& externalStorageDirPath.endsWith("/")) {
externalStorageDirPath = externalStorageDirPath.substring(0,
externalStorageDirPath.length() - 1);
}
String[] pathElements = externalStorageDirPath.split("/");
for (int i = 0; i < pathElements.length - 1; i++) {
rootDir = rootDir.getParentFile();
}
File[] files = rootDir.listFiles();
for (File file : files) {
if (file.exists() && file.compareTo(innerDir) != 0) {
// Try-catch is implemented to prevent from any IO exception
try {
if (Environment.isExternalStorageRemovable(file)) {
return file.getAbsolutePath();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
如果您有其他处理此问题的方法,请分享。谢谢。
grep
出现了一些问题。无论如何,逻辑是从mount
命令中获取存储卡目录。你可以通过其他方法获取shell并执行命令并处理输出。 - Gokul NC在我的HTC One X(Android)中访问SD卡中的文件,我使用以下路径:
file:///storage/sdcard0/folder/filename.jpg
注意三个斜杠!
您可以使用类似于Context.getExternalCacheDirs()、Context.getExternalFilesDirs()或Context.getObbDirs()的方法。它们提供了应用程序特定目录,可以在所有外部存储设备中存储其文件。
因此,像这样的代码 - Context.getExternalCacheDirs()[i].getParentFile().getParentFile().getParentFile().getParent() 可以获取外部存储设备的根路径。
我知道这些命令是为不同的目的而设计的,但其他答案对我没有用。
这个链接给了我很好的指导 - https://possiblemobile.com/2014/03/android-external-storage/