大多数新的 android 设备都有一个内部 sdcard 和一个外部 sdcard。我想制作一个文件资源管理器应用程序,但我不知道如何获取在我的应用程序中使用的路径,因为
File file = Environment.getExternalStorageDirectory();
只是在大多数设备中返回,/mnt/sdcard
但其他外部 SD 卡还有另一条路径,例如/storage1 or /storage2
. 任何帮助表示赞赏。
大多数新的 android 设备都有一个内部 sdcard 和一个外部 sdcard。我想制作一个文件资源管理器应用程序,但我不知道如何获取在我的应用程序中使用的路径,因为
File file = Environment.getExternalStorageDirectory();
只是在大多数设备中返回,/mnt/sdcard
但其他外部 SD 卡还有另一条路径,例如/storage1 or /storage2
. 任何帮助表示赞赏。
如何在android中获取内部和外部sdcard路径
存储在内部存储中的方法:
File getDir (String name, int mode)
File getFilesDir ()
以上方法存在于Context
类中
存储在手机内存中的方法:
File getExternalStorageDirectory ()
File getExternalFilesDir (String type)
File getExternalStoragePublicDirectory (String type)
一开始大家都用Environment.getExternalStorageDirectory()
,指向手机内存的根。结果,根目录充满了随机内容。
后来又增加了这两个方法:
在Context
课堂上,他们添加了getExternalFilesDir()
,指向手机内存中的特定应用目录。卸载应用程序时,该目录及其内容将被删除。
Environment.getExternalStoragePublicDirectory()
用于存储知名文件类型(如照片和电影)的集中位置。卸载应用程序时,该目录及其内容不会被删除。
存储在可移动存储(即微型 SD 卡)中的方法
在 API 级别 19 之前,没有官方的方式存储在 SD 卡中。但是许多人可以使用非官方的 API 来做到这一点。
正式地,在API 级别 19(Android 版本 4.4 - Kitkat)的Context
类中引入了一种方法。
File[] getExternalFilesDirs (String type)
它返回所有共享/外部存储设备上应用程序特定目录的绝对路径,应用程序可以在其中放置其拥有的持久文件。这些文件是应用程序内部的,通常不会作为媒体对用户可见。
这意味着,它将返回到 Micro SD 卡和内部存储器的路径。通常,第二个返回路径是 micro SD 卡的存储路径。
根据 Google/官方 Android 文档的内部和外部存储术语与我们的想法有很大不同。
是的。不同的制造商使用不同的 SD 卡名称,如三星 Tab 3 它的 extsd,而其他三星设备使用不同的 SD 卡,不同的制造商使用不同的名称。
我和你有同样的要求。所以我从我的项目中为您创建了一个示例示例转到此链接Android 目录选择器示例,该示例使用 android-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/etc/vold.fstab 文件并查找如下行:dev_mount sdcard /mnt/sdcard 1 /devices/platform/s3c-sdhci.0/ mmc_host/mmc0
找到一个后,将其拆分为其元素,然后拉出该挂载点的路径并将其添加到 arraylist
强调文本一些设备完全缺少vold文件,所以我们在这里添加一个路径以确保列表始终包含第一个sdcard的路径,无论是真实的还是模拟的。
sVold.add("/mnt/sdcard");
try {
Scanner scanner = new Scanner(new File("/system/etc/vold.fstab"));
while (scanner.hasNext()) {
String line = scanner.nextLine();
if (line.startsWith("dev_mount")) {
String[] lineElements = line.split(" ");
String element = lineElements[2];
if (element.contains(":"))
element = element.substring(0, element.indexOf(":"));
if (element.contains("usb"))
continue;
// don't add the default vold path
// it's already in the list.
if (!sVold.contains(element))
sVold.add(element);
}
}
} catch (Exception e) {
// swallow - don't care
e.printStackTrace();
}
}
现在我们已经有了一个干净的挂载路径列表,测试每个路径以确保它是有效且可用的路径。如果不是,请将其从列表中删除。
private static void testAndCleanList()
{
for (int i = 0; i < sVold.size(); i++) {
String voldPath = sVold.get(i);
File path = new File(voldPath);
if (!path.exists() || !path.isDirectory() || !path.canWrite())
sVold.remove(i--);
}
}
我不确定这个答案有多普遍,但我在装有 Android 4.4 的摩托罗拉 XT830C 和 Nexus 7 android 6.0.1 上对其进行了测试。在三星 SM-T530NU Android 5.0.2 上。我用System.getenv("SECONDARY_STORAGE")
和Environment.getExternalStorageDirectory().getAbsolutePath()
。
没有第二张 SD 卡的 NexusSystem.getenv
返回 null 并Envirnoment.getExterna...
给出 /storage/emulated/0。
具有外部 SD 卡的摩托罗拉设备为 /storage/sdcard1System.getenv("SECONDARY_STORAGE")
提供Envirnoment.getExterna...
/storage/emulated/0。
samsumg 为外部 SD 返回 /storage/extSdCard。
就我而言,我正在外部位置创建一个子目录并使用
appDirectory = (System.getenv("SECONDARY_STORAGE") == null)
? Environment.getExternalStorageDirectory().getAbsolutePath()
: System.getenv("SECONDARY_STORAGE");
找到SD卡。在这个目录中创建一个子目录是有效的。
当然,我必须在清单文件中设置访问外部存储器的权限。
我还有一个 Nook 8" 彩色平板电脑。当我有机会对其进行测试时,如果我对这种方法有任何问题,我会发布。
但其他外部 sdcard 有另一条路径,如 /storage1 或 /storage2
Android SDK 中没有任何东西——至少通过 Android 4.1——可以让您访问这些路径。无论如何,您的应用程序可能无法读取或写入它们。此类存储位置的行为及其用途取决于设备制造商。
对于所有 Android 版本,
权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />
使用 Android 10 的 requestLegacyExternalStorage(添加到 AndroidManifest > application 标签):
android:requestLegacyExternalStorage="true"
获取内部目录路径:
@Nullable
public static String getInternalStorageDirectoryPath(Context context) {
String storageDirectoryPath;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
if(storageManager == null) {
storageDirectoryPath = null; //you can replace it with the Environment.getExternalStorageDirectory().getAbsolutePath()
} else {
storageDirectoryPath = storageManager.getPrimaryStorageVolume().getDirectory().getAbsolutePath();
}
} else {
storageDirectoryPath = Environment.getExternalStorageDirectory().getAbsolutePath();
}
return storageDirectoryPath;
}
获取外部目录:
@NonNull
public static List<String> getExternalStorageDirectoryPaths(Context context) {
List<String> externalPaths = new ArrayList<>();
String internalStoragePath = getInternalStorageDirectoryPath(context);
File[] allExternalFilesDirs = ContextCompat.getExternalFilesDirs(context, null);
for(File filesDir : allExternalFilesDirs) {
if(filesDir != null) {
int nameSubPos = filesDir.getAbsolutePath().lastIndexOf("/Android/data");
if(nameSubPos > 0) {
String filesDirName = filesDir.getAbsolutePath().substring(0, nameSubPos);
if(!filesDirName.equals(internalStoragePath)) {
externalPaths.add(filesDirName);
}
}
}
}
return externalPaths;
}
File main=new File(String.valueOf(Environment.getExternalStorageDirectory().getAbsolutePath()));
File[]t=main.getParentFile().listFiles();
for(File dir:t)
{
Log.e("Main",dir.getAbsolutePath());
}
输出:
E/Main: /storage/sdcard1
E/Main: /storage/sdcard0
我有一张 SD 卡和内置内存。
试试这个代码,它会有所帮助
Map<String, File> externalLocations = ExternalStorage.getAllStorageLocations();
File sdCard = externalLocations.get(ExternalStorage.SD_CARD);
File externalSdCard = externalLocations.get(ExternalStorage.EXTERNAL_SD_CARD);
没有用于获取内部/外部 sdcard 路径的公共 api。
但是在 android.os.storage 包中有一个叫做 StorageManager 的平台 api。见http://goo.gl/QJj1eu。
有列表存储、挂载/卸载存储、获取挂载状态、获取存储路径等功能。
但它是隐藏的 api,它应该在下一个 android 版本中被弃用或破坏。
并且有些方法需要特别许可,而且大多数都没有记录在案。