android Q beta中的文件操作

Posted

技术标签:

【中文标题】android Q beta中的文件操作【英文标题】:File operations in android Q beta 【发布时间】:2019-12-13 16:33:40 【问题描述】:

1)目标设置为android Qandroid.permission.WRITE_EXTERNAL_STORAGE

2) 使用getExternalStorageDirectorygetExternalStoragePublicDirectoryFileOutputStream(file)保存文件抛出

java.io.FileNotFoundException: /storage/emulated/0/myfolder/mytext.txt open failed: ENOENT (No such file or directory)

3) 使用getExternalFilesDirapi 并保存成功,但即使在MediaScannerConnection.scanFile 之后也不会显示。

     /storage/emulated/0/Android/data/my.com.ui/files/Download/myfolder/mytext.txt

在android Q中将文件从内部存储器复制到SDCARD并刷新的最佳方法是什么。

【问题讨论】:

【参考方案1】:

在 Android Manifest 的 <application> 标签中添加 android:requestLegacyExternalStorage="true",这将允许您暂时使用所有文件 API。

【讨论】:

是的,它可以工作。想要在没有那个选项的情况下让它工作。 @NitZRobotKoder 除了使用 SAF 之外别无他法。 你的意思是这样吗?developer.android.com/guide/topics/providers/… “别无他法”:您也可以从 Android R+ 开始放弃支持并完全忽略该平台。总有一些选择...... :)(我没有投反对票,但很高兴提到这个标志只是Android Q的临时标志,但另一个答案无论如何都更完整......虽然它可能有更明确地提到了 SAF(我只是在这里吃爆米花)) android:requestLegacyExternalStorage="true"【参考方案2】:

在 Android Q 中,对于私有文件夹之外的应用,默认情况下禁用直接文件访问。您可以使用以下几种策略:

    使用 manifest 选项 requestLegacyStorage 来获得旧行为,但它不再适用于 Android R,因此它确实是一个短期解决方案; 使用getExternalFilesDir() 方法保存文件。这是您的私人文件夹,其他应用只有拥有READ_EXTERNAL_STORAGE 权限才能访问这些文件。在这种情况下,最好使用 FileProvider 授予对您文件的其他应用程序的访问权限。 使用MediaStore API 直接插入您的媒体。这种方法适用于视频、音乐和照片。 使用StorageManager 类的方法getPrimaryStorageVolume().createOpenDocumentTreeIntent() 请求访问外部主卷。在这种情况下,您需要用户同意并且无论如何您将无法直接使用File api,但是使用DocumentFile 类您有一个非常相似的界面,所以这是更接近旧行为的解决方案。如果您需要在前台和后台执行操作,即无需用户交互,但请求权限的第一次交互除外。 使用ACTION_CREATE_DOCUMENT 创建一个使用SAF 的文件。如果您在前台执行此操作,此选项有效,因为您需要用户选择文件夹。

我为第 4 点链接了 Flipper 库,它有助于像在旧的 android 版本中一样管理文件。

【讨论】:

developer.android.com/guide/topics/providers/… 能够使用它来工作。 是否可以选择创建我的名字的文件夹并通过 Document-provider 复制到 SDCARD 中? 不是直接的,但您可以使用选项 4 使用方法 getStorageVolumes 返回的可移动非主存储来询问 SdCard 访问 @greywolf82 能否请您进一步解释这一点:3 - 使用 MediaStore API 直接插入您的媒体。这种方法适用于视频、音乐和照片。 @greywolf82 我认为我在 android 10 beta 版本中遇到了与 File API 相同的问题。我已经用存储访问框架修复了它。但是在 android Q 官方发布版本中,FileOutputStream(file) 不再抛出这个异常。我没有使用requestLegacyStorage = true,并且我的 tagetsdk 和 compileSdk 是 29。谷歌在最终版本中是否更改了任何内容?【参考方案3】:

1)使用文档提供者https://developer.android.com/guide/topics/providers/document-provider#create

2)将要求用户保存(文件总数)并存储在文档文件夹中。 https://gist.github.com/neonankiti/05922cf0a44108a2e2732671ed9ef386

【讨论】:

【参考方案4】:

在 Android API 29 及更高版本中,您可以使用以下代码将文件、图像和视频存储到外部存储。

//首先,如果您使用“android.media.action.IMAGE_CAPTURE”选择文件 然后将该文件存储在应用程序私有 Path(getExternalFilesDir()) 中,如下所示。

File destination = new File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), fileName);

//然后使用content provider来访问Media-store,如下所示。

 ContentValues values = new ContentValues(); 
 values.put(MediaStore.Images.Media.TITLE, fileName); 
 values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);

//如果您想要特定的 mime 类型,请在此处指定您的 mime 类型。否则留空,它将采用默认文件mime类型

values.put(MediaStore.Images.Media.MIME_TYPE, "MimeType"); 
values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis() / 1000); 
values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis()); 
values.put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/" + "path"); // specify 
 storage path

// 使用内容提供者插入媒体存储,它将返回 URI。

Uri uri = cxt.getContentResolver().insert(MediaStore.Files.getContentUri("external"), values); 

//使用该URI打开文件。

ParcelFileDescriptor descriptor = context.getContentResolver().openFileDescriptor(uri,"w"); //"w" specify's write mode
FileDescriptor fileDescriptor = descriptor.getFileDescriptor();

// 从私有路径读取文件。

InputStream dataInputStream = cxt.openFileInput(privatePath_file_path);

//将文件写入输出文件流。

 OutputStream output = new FileOutputStream(fileDescriptor);
 byte[] buf = new byte[1024];
 int bytesRead;
 while ((bytesRead = dataInputStream.read(buf)) > 0) 
 
  output.write(buf, 0, bytesRead);
 
 datanputStream.close();
 output.close();

【讨论】:

如何检查文件是否存在。 私有文件路径是什么? 目的地在哪里使用? 不适合我。尝试将privatePath_file_path 设置为路径并引发异常,因为参数包含路径分隔符:尝试仅放置文件名但失败,因为它查找/data/my.app.package/files/myFile(而它应该查找/storage/emulated/0/Android/data/my.app.package/files/myfile 私有路径:data/user/0/com.mypakage.ui/files【参考方案5】:

暂时的可能性:你可以在Android Manifest的<application>标签中使用android:requestLegacyExternalStorage="true"

【讨论】:

你的回答和***.com/a/57370857/5550161有什么区别【参考方案6】:

如果您使用 preserveLegacyExternalStorage,则旧版存储模型仅在用户卸载您的应用之前仍然有效。如果用户在运行 Android 11 的设备上安装或重新安装您的应用,那么无论 preserveLegacyExternalStorage 的值如何,您的应用都无法选择退出范围存储模型。

使用此标志时要记住的事项。 know more

【讨论】:

以上是关于android Q beta中的文件操作的主要内容,如果未能解决你的问题,请参考以下文章

Android Transform API的使用

Android Transform API的使用

如何解决“在Android独立路径中找到多个文件'project.properties'”Android Studio 3.0 Beta-6中的错误

联想杨元庆:没必要做操作系统和芯片;华为Mate 20 Pro被迫退出安卓 Q Beta;GitHub推赚钱新利器 | 极客头条

从 Fabric Beta 下载 Android APK 文件

让最新的 Android Q Beta 3 强制重启的 Project Mainline,到底是什么?