【问题标题】:Android write file on External SD Card for android 5+Android 在外部 SD 卡上写入文件,适用于 android 5+
【发布时间】:2016-05-03 16:37:10
【问题描述】:

我无法将文件写入外部 SD 卡。 我收到错误消息 EAcess denied。我在互联网上搜索了很多,发现从 Android 4.4 + android 的存储访问框架(SAF)需要写入文件。

但我正在使用一些能够在 SD 卡上写入(创建/删除/重命名)文件的 android 应用程序。他们没有使用 SAF。

所以请帮助我了解如何在不使用 SAF 框架的情况下做到这一点。

谢谢

【问题讨论】:

  • 请问您可以将代码发布到您尝试在外部 SD 上写入文件的位置吗?另外,你声明<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>了吗?
  • 澄清一下,您是要写入模拟 SD 还是物理外部存储?
  • @Grender 是的,我已经在清单文件中的正确位置添加了用户权限。我也重新检查了。
  • @Daniel 物理外部存储

标签: android file-io android-sdcard android-file


【解决方案1】:

关于 Android 的外部存储器有很多困惑。它实际上并不指向可移动 SD MICRO CARD。那么,谷歌认为“外部存储器”是什么意思

参考Android API Document

每台兼容 Android 的设备都支持共享的“外部存储” 您可以用来保存文件。这可以是可移动存储介质 (例如 SD 卡)或内部(不可移动)存储。文件 保存到外部存储是世界可读的并且可以修改 当用户启用 USB 大容量存储以在 电脑。

事实是 Environment.getExternalStorageDirectory() 和 Context.getExternalFilesDirs() 可以返回位于内部存储内部的模拟外部存储器。因此,这些函数本身并没有给出预期的结果。 SECONDARY_STORAGE 环境变量可以帮助获得可移动内存的真实路径,但由于 OEM 实施,不允许在其根目录上写入。在这种情况下,我们应该尝试通过 Context.getExternalFilesDirs() 或 ContextCompat.getExternalFilesDirs() 获取应用程序的数据文件夹,在该文件夹上允许读取和写入应用程序的数据文件。

我通过以下方法解决了我的问题,请检查一下,希望它可以帮助您解决问题。

@TargetApi(Build.VERSION_CODES.KITKAT)
private String getRemovablePath(){
    String secondaryStore = System.getenv("SECONDARY_STORAGE");     
    if (secondaryStore != null){
        secondaryStore = secondaryStore.split(":")[0];
        secondaryStore += File.separator + "Backups/";
        File file = new File(secondaryStore);
        if((file.mkdir() || file.isDirectory()) && isFileWritable(secondaryStore)){
            return secondaryStore;
        } else {
            secondaryStore = null;
        }           
    } 

    // try again by fix address
    if(secondaryStore == null){
        if (new File("/Removable/MicroSD/").exists()){              
            secondaryStore = "/Removable/MicroSD/";
        } else if( new File("/storage/extSdCard/").exists()){
            secondaryStore = "/storage/extSdCard/";
        } else if( new File("/storage/sdcard1/").exists()){
            secondaryStore = "/storage/sdcard1/";
        } else if( new File("/storage/usbcard1/").exists()){
            secondaryStore = "/storage/usbcard1/";
        } else if( new File("/storage/external_SD/").exists()){
            secondaryStore = "/storage/external_SD/";
        }   
        /** add more fix addresses you know */
        secondaryStore += "Backups/";
        File file = new File(secondaryStore);
        if((file.mkdir() || file.isDirectory()) && isFileWritable(secondaryStore)){                             
            return secondaryStore;
        } else {
            secondaryStore = null;
        }           

    }       
    /** Try data folder*/
    if(secondaryStore == null){         
        int ver = Build.VERSION.SDK_INT;
        File[] externalRoots = null;
        if(ver <= Build.VERSION_CODES.JELLY_BEAN_MR2){          
            externalRoots = ContextCompat.getExternalFilesDirs(getBaseContext(), null);
        } else {
            externalRoots = getExternalFilesDirs(null);
        }   

        if(externalRoots.length > 1){
            secondaryStore = externalRoots[1].getAbsolutePath() + File.separator;
            return secondaryStore;
        } else {
            secondaryStore = null;
        }               
    }


    return secondaryStore;          
}

【讨论】:

    【解决方案2】:

    请检查链接,如果存在问题:

    issue

    在以前的 android 版本中访问外部存储器没有问题。目前拥有改进

    【讨论】:

      【解决方案3】:

      Android API

      您的 Android Manifest 必须声明特定的用户权限:

      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
      

      如果您还打算读取文件,您还必须声明读取权限:

      <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
      

      用户权限必须放在应用部分之前,像这样:

      <manifest> 
          <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
      
            ...
      
          <application>
      

      我的解释和如何保存文件的例子可以在official documentation找到。

      Android 6 (API 23)

      从 Android API 23 开始,情况会有所不同,因为在需要时必须在运行时向用户询问用户权限。 here 已经给出了对此的有效答案。

      【讨论】:

      • 见过这个东西,这只适用于模拟SD卡(内部存储)
      • @AnkeshkumarJaisansaria 我做了进一步的研究,似乎从 Android 4.4 开始,第三方应用程序(更准确地说不是 OEM)在物理 SD 卡上写入的唯一选择是通过 SAF 框架。正式的应用程序应该只访问它们在 SD 卡上保留的应用程序文件夹。
      • 如果您的 targetApiLevel=22,此方法有效。即使在 Android M 设备上也会自动授予权限
      【解决方案4】:

      仅当您必须写入 SD 卡上的任何位置时才需要 SAF。要写入 SD 卡上的应用程序特定目录,您可以使用 context.getExternalFilesDirs。返回的路径之一将是您的应用程序特定文件夹在 SD 卡上的路径。

      同样,这也取决于制造商。如果厂商没有设置 SECONDARY_STORAGE 环境变量,getExternalFilesDirs 返回的路径将不包含 SD 卡路径。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多