安卓手机无法将文件保存到SD卡

4

我希望能将一个文本文件保存到插入在运行lollipop系统的HTC One M8手机中的SD卡上。然而,当我运行此代码时,它保存到内部存储器而不是SD卡。

String FILENAME = "mysavefile.txt";

    File file = new File(Environment.getExternalStorageDirectory(), FILENAME);

    if (isExternalStorageWritable()) {
        errorSD.setVisibility(View.INVISIBLE);
        try {
            FileOutputStream fos = new FileOutputStream(file, false);
            fos.write(allInformation.getBytes(), 0, 81);
            fos.close();
            successfulSubmissionToast();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            errorSD.setVisibility(View.VISIBLE);
        } catch (IOException e) {
            e.printStackTrace();
        }

它应该保存到

/storage/ext_sd

但实际上它保存到了。
/storage/emulated/0

然后我尝试手动输入我的SD卡位置,看看是否能够解决问题,但最终出现了FileNotFoundException异常。

File file = new File("/storage/ext_sd", FILENAME);

编辑: 我认为问题在于有多个外部存储设备,其中一个是永久的,另一个是临时的。问题是如何访问第二个。


1
你尝试过阅读使用外部存储的文档吗? - alanv
它将文件保存在内部存储的哪个位置? - Daniel Nugent
它当然没有 - 它将其保存在外部存储器上,但不是在SD卡上,这显然是该设备上某种次要的外部存储器。供应商以不一致的方式处理此问题。 - Chris Stratton
它将其保存到内部存储的最外层文件中,其中包括电影、音乐、下载等文件夹。/storage/emulated/0 - jtreiner
那不是内部存储位置,而是外部存储位置,只是不在SD卡上。 "external"指的是API,而不是物理特征。 - Chris Stratton
显示剩余5条评论
4个回答

2

首先,我们需要了解内部存储、外部存储(也称为主要外部存储)和次要外部存储之间的区别。

内部存储:是用户无法访问的存储,除非通过安装的应用程序(或通过对设备进行root操作)来访问。例如:data/data/app_packageName。

主要外部存储:内置的共享存储,用户可以通过连接USB电缆并将其挂载为主机计算机上的驱动器来访问。例如:当我们说Nexus 5 32 GB时。

次要外部存储:可移动存储。例如:SD卡。

getExternalStorageDirectory ()

它将返回主要外部存储目录的路径。

要访问可移动的SD卡(次要的外部存储),有以下API:

getExternalFilesDirs(),getExternalCacheDirs()getExternalMediaDirs()

请查阅相关文档以获取更多信息。


1
如果在处理多个外部存储时,Android设备遵循此处的指南,我们可以使用以下代码来检测在Android kitkat或更高版本中写入数据的位置。
    final String APP_EXTERNAL_CACHE = "Android" + File.separator + "data"
            + File.separator + getPackageName() + File.separator + "cache";
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        for (File file : getExternalCacheDirs()) {
            if (file != null) {
                String mountPoint = file.getAbsolutePath().replace(APP_EXTERNAL_CACHE, "");

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    if (Environment.isExternalStorageRemovable(file)) {
                        Log.d(TAG, "removable external " + file.getAbsolutePath());
                    }
                    if (Environment.isExternalStorageEmulated(file)) {
                        Log.d(TAG, "emulated internal " + file.getAbsolutePath());
                    }
                } else {
                    if (mountPoint.contains("emulated")) {
                        Log.d(TAG, "emulated internal " + mountPoint);
                    } else {
                        Log.d(TAG, "removable external " + mountPoint);
                    }
                }
            }
        }
    }

在清单文件中声明相关权限。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

1
我希望将文本文件保存到插入到运行棒棒糖的HTC One M8中的SD卡中。您可以尝试Context上的getExternalFilesDirs(),getExternalCacheDirs()和getExternalMediaDirs()方法,注意方法名的复数形式。对于这些方法,如果它们返回多个条目,则第二个及后续条目应在可移动介质上,指向可以读写的目录,无需任何特殊权限(例如WRITE_EXTERNAL_STORAGE)。除了这些位置之外,对于预装Android 4.4+的设备,您无法访问可移动存储。

-1

我觉得这是因为HTC One修改了sdcard的挂载点,你可以尝试使用adb shell ls -l命令来找出sdcard挂载在哪个路径下。

例如,在Nexus 4中:

lrwxrwxrwx root     root              2015-03-24 18:26 sdcard -> /storage/emulated/legacy
drwxr-x--x root     sdcard_r          2015-03-24 18:26 storage

而且你应该确保它不是链接:ls -l /storage/emulated/legacy

lrwxrwxrwx root     root              2015-03-24 18:26 legacy -> /mnt/shell/emulated/0

/mnt/shell/emulated/0 路径实际上是 sdcard 路径。

尝试阅读如何获取 Android 4.0+ 的外部 SD 卡路径?,这可能会对你有很大帮助。

更新

我尝试了这段代码:

    String test = "/storage/emulated/legacy"; // work
    //String test = "/mnt/shell/emulated/legacy"; // not work
    File sdDir = new File(test);
    if (sdDir.exists()) {
        File file = new File(test, "test.sdcard");
        try {
            file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

所以,您最好尝试使用/storage/emulated/*目录来确定哪个是您的SD卡。


实际上,不能使用ADB shell查找应用程序挂载的位置,因为ADB和应用程序的挂载点不同。但是,您可以使用文件管理器应用程序或终端模拟器,因为它们(至少到目前为止)通常适用于不同的应用程序。 - Chris Stratton
我使用文件管理器发现 /storage/ext_sd 是 SD 卡所在的位置,而 /storage/emulated/0 不是 SD 卡。我知道这是因为我取出了 SD 卡,但 /storage/emulated/0 仍然存在,而 /storage/ext_sd 则消失了。 - jtreiner
根据您的目标这可能有帮助 - 即,它是针对特定 Android 版本在特定设备上的答案。但这绝不是一种可移植的答案。您也可能发现您没有以那种方式访问权限。 - Chris Stratton
对我来说,在/storage/emulated/下有两个文件。0和legacy。但它们都指向同一个东西,都不是SD卡。 - jtreiner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接