有没有一种通用的方法来找到外置SD卡的位置?
请不要与外部存储混淆。
Environment.getExternalStorageState()返回内部SD挂载点的路径,例如/mnt/sdcard。但问题是关于外部SD的。我如何获得类似/mnt/sdcard/external_sd的路径(它可能因设备而异)?
我想我将以根据文件系统名称过滤mount命令的输出作为结束。但我不确定这种方式是否足够稳健。
有没有一种通用的方法来找到外置SD卡的位置?
请不要与外部存储混淆。
Environment.getExternalStorageState()返回内部SD挂载点的路径,例如/mnt/sdcard。但问题是关于外部SD的。我如何获得类似/mnt/sdcard/external_sd的路径(它可能因设备而异)?
我想我将以根据文件系统名称过滤mount命令的输出作为结束。但我不确定这种方式是否足够稳健。
当前回答
由于上面我最初的回答,扫描vold在各个制造商中不再可行。
我发明了一种更可靠更直接的方法。
File mnt = new File("/storage");
if (!mnt.exists())
mnt = new File("/mnt");
File[] roots = mnt.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isDirectory() && pathname.exists()
&& pathname.canWrite() && !pathname.isHidden()
&& !isSymlink(pathname);
}
});
根目录将包含系统上所有可写的根目录,包括任何usb连接的usb设备。
注意:canWrite方法需要android.permission。WRITE_EXTERNAL_STORAGE许可。
其他回答
这么晚了,但最终我得到了一些东西,我已经测试了大多数设备(通过制造商和android版本),它在android 2.2+上工作。如果您发现它不起作用,请用您的设备名称注释它。我会解决的。如果有人感兴趣,我会解释它是如何工作的。
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStreamReader;
import android.util.Log;
/**
* @author ajeet
*05-Dec-2014 2014
*
*/
public class StorageUtil {
public boolean isRemovebleSDCardMounted() {
File file = new File("/sys/class/block/");
File[] files = file.listFiles(new MmcblkFilter("mmcblk\\d$"));
boolean flag = false;
for (File mmcfile : files) {
File scrfile = new File(mmcfile, "device/scr");
if (scrfile.exists()) {
flag = true;
break;
}
}
return flag;
}
public String getRemovebleSDCardPath() throws IOException {
String sdpath = null;
File file = new File("/sys/class/block/");
File[] files = file.listFiles(new MmcblkFilter("mmcblk\\d$"));
String sdcardDevfile = null;
for (File mmcfile : files) {
Log.d("SDCARD", mmcfile.getAbsolutePath());
File scrfile = new File(mmcfile, "device/scr");
if (scrfile.exists()) {
sdcardDevfile = mmcfile.getName();
Log.d("SDCARD", mmcfile.getName());
break;
}
}
if (sdcardDevfile == null) {
return null;
}
FileInputStream is;
BufferedReader reader;
files = file.listFiles(new MmcblkFilter(sdcardDevfile + "p\\d+"));
String deviceName = null;
if (files.length > 0) {
Log.d("SDCARD", files[0].getAbsolutePath());
File devfile = new File(files[0], "dev");
if (devfile.exists()) {
FileInputStream fis = new FileInputStream(devfile);
reader = new BufferedReader(new InputStreamReader(fis));
String line = reader.readLine();
deviceName = line;
}
Log.d("SDCARD", "" + deviceName);
if (deviceName == null) {
return null;
}
Log.d("SDCARD", deviceName);
final File mountFile = new File("/proc/self/mountinfo");
if (mountFile.exists()) {
is = new FileInputStream(mountFile);
reader = new BufferedReader(new InputStreamReader(is));
String line = null;
while ((line = reader.readLine()) != null) {
// Log.d("SDCARD", line);
// line = reader.readLine();
// Log.d("SDCARD", line);
String[] mPonts = line.split("\\s+");
if (mPonts.length > 6) {
if (mPonts[2].trim().equalsIgnoreCase(deviceName)) {
if (mPonts[4].contains(".android_secure")
|| mPonts[4].contains("asec")) {
continue;
}
sdpath = mPonts[4];
Log.d("SDCARD", mPonts[4]);
}
}
}
}
}
return sdpath;
}
static class MmcblkFilter implements FilenameFilter {
private String pattern;
public MmcblkFilter(String pattern) {
this.pattern = pattern;
}
@Override
public boolean accept(File dir, String filename) {
if (filename.matches(pattern)) {
return true;
}
return false;
}
}
}
这次我尝试了这个主题内的所有解决方案。但是,在有一个外置卡(可移动)和一个内置卡(不可移动)的设备上,所有这些设备都不能正常工作。外部卡的路径不可能从'mount'命令,从'proc/mounts'文件等。
我在Paulo Luan的基础上提出了自己的解决方案:
String sSDpath = null;
File fileCur = null;
for( String sPathCur : Arrays.asList( "ext_card", "external_sd", "ext_sd", "external", "extSdCard", "externalSdCard")) // external sdcard
{
fileCur = new File( "/mnt/", sPathCur);
if( fileCur.isDirectory() && fileCur.canWrite())
{
sSDpath = fileCur.getAbsolutePath();
break;
}
}
fileCur = null;
if( sSDpath == null) sSDpath = Environment.getExternalStorageDirectory().getAbsolutePath();
你可以尝试使用支持库函数ContextCompat.getExternalFilesDirs():
final File[] appsDir=ContextCompat.getExternalFilesDirs(getActivity(),null);
final ArrayList<File> extRootPaths=new ArrayList<>();
for(final File file : appsDir)
extRootPaths.add(file.getParentFile().getParentFile().getParentFile().getParentFile());
第一个是主要的外部存储,其余的应该是真正的sd卡路径。
使用多个“.getParentFile()”的原因是要转到另一个文件夹,因为原始路径是
.../Android/data/YOUR_APP_PACKAGE_NAME/files/
编辑:这是一个更全面的方法,我已经创建,以获得sd卡路径:
/**
* returns a list of all available sd cards paths, or null if not found.
*
* @param includePrimaryExternalStorage set to true if you wish to also include the path of the primary external storage
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static List<String> getSdCardPaths(final Context context, final boolean includePrimaryExternalStorage)
{
final File[] externalCacheDirs=ContextCompat.getExternalCacheDirs(context);
if(externalCacheDirs==null||externalCacheDirs.length==0)
return null;
if(externalCacheDirs.length==1)
{
if(externalCacheDirs[0]==null)
return null;
final String storageState=EnvironmentCompat.getStorageState(externalCacheDirs[0]);
if(!Environment.MEDIA_MOUNTED.equals(storageState))
return null;
if(!includePrimaryExternalStorage&&VERSION.SDK_INT>=VERSION_CODES.HONEYCOMB&&Environment.isExternalStorageEmulated())
return null;
}
final List<String> result=new ArrayList<>();
if(includePrimaryExternalStorage||externalCacheDirs.length==1)
result.add(getRootOfInnerSdCardFolder(externalCacheDirs[0]));
for(int i=1;i<externalCacheDirs.length;++i)
{
final File file=externalCacheDirs[i];
if(file==null)
continue;
final String storageState=EnvironmentCompat.getStorageState(file);
if(Environment.MEDIA_MOUNTED.equals(storageState))
result.add(getRootOfInnerSdCardFolder(externalCacheDirs[i]));
}
if(result.isEmpty())
return null;
return result;
}
/** Given any file/folder inside an sd card, this will return the path of the sd card */
private static String getRootOfInnerSdCardFolder(File file)
{
if(file==null)
return null;
final long totalSpace=file.getTotalSpace();
while(true)
{
final File parentFile=file.getParentFile();
if(parentFile==null||parentFile.getTotalSpace()!=totalSpace||!parentFile.canRead())
return file.getAbsolutePath();
file=parentFile;
}
}
编辑:这里有更好的解决方案:
https://stackoverflow.com/a/27197248/878126
通过编写下面的代码,您将获得位置:
数据存储663D-554E / Android / app_package_name / files /
存储你的应用程序数据在/android/数据位置内的sd_card。
File[] list = ContextCompat.getExternalFilesDirs(MainActivity.this, null);
list[1]+"/fol"
对于获取位置,内部传递0,sdcard传递1到文件数组。
我已经在moto g4 plus和三星设备上测试了这段代码(一切正常)。
希望这对你有所帮助。
只要简单地使用这个:
String primary_sd = System.getenv("EXTERNAL_STORAGE");
if(primary_sd != null)
Log.i("EXTERNAL_STORAGE", primary_sd);
String secondary_sd = System.getenv("SECONDARY_STORAGE");
if(secondary_sd != null)
Log.i("SECONDARY_STORAGE", secondary_sd)