android Q beta中的文件操作
Posted
技术标签:
【中文标题】android Q beta中的文件操作【英文标题】:File operations in android Q beta 【发布时间】:2019-12-13 16:33:40 【问题描述】:1)目标设置为android Q
和android.permission.WRITE_EXTERNAL_STORAGE
2) 使用getExternalStorageDirectory
或getExternalStoragePublicDirectory
和FileOutputStream(file)
保存文件抛出
java.io.FileNotFoundException: /storage/emulated/0/myfolder/mytext.txt open failed: ENOENT (No such file or directory)
3) 使用getExternalFilesDir
api 并保存成功,但即使在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独立路径中找到多个文件'project.properties'”Android Studio 3.0 Beta-6中的错误
联想杨元庆:没必要做操作系统和芯片;华为Mate 20 Pro被迫退出安卓 Q Beta;GitHub推赚钱新利器 | 极客头条