在Android 10 文件储存机制修改为沙盒模式,
App 只能访问自己目录下的文件和公共媒体文件,
所以,即使获取了存储的权限,访问外部的存储受到了限制,也就是说除了自己目录和公共媒体文件,
读取其它的文件就会报:open failed: EACCES (Permission denied)。
解决方法:
第一种方法:在 AndroidManifest.xml 的 application 添加属性:
android:requestLegacyExternalStorage=“true”
这代码意思是使用旧存储方式,但不建议使用此法,因为在Android 10以后该配置就会失效!
(写了该配置启动app又删除该配置又启动app,就不会报错,因为已经记录了用该配置存储,当卸载再重新安装,又会报错)
第二种:既然无法读取file(可以获得file实例,不能读取(使用)),那就通过该file的uri创建
新的一样内容的file在自己的目录下,再读取新的file即可
以下是根据uri创建新的file的代码:
//====根据 uri(content或file开头都行)生成新的file
public File getFile(Uri uri) {
//https://www.jb51.net/article/181745.htm
//文件夹 这两种文件夹都会随软件卸载而删掉
File folder = this.getExternalCacheDir();//在Android>data>包名>的cache目录下,一般存放临时缓存数据
//File folder = this.getExternalFilesDir("image");//在Android>data>包名>的files的image目录下,一般放一些长时间保存的数据
if (!folder.exists()){
folder.mkdir();
}
//file图片
File file=new File(folder.getAbsolutePath()+File.separator+"newFile.jpg");
try {
//根据uri获取输入字节流
InputStream inputStream = getContentResolver().openInputStream(uri);
//==把输入流写进file里
FileOutputStream fileOutputStream=new FileOutputStream(file);
byte[] buffer=new byte[1024];
int byteRead;
while (-1 != (byteRead=inputStream.read(buffer))){
fileOutputStream.write(buffer,0,byteRead);
}
fileOutputStream.flush();
inputStream.close();
fileOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return file;
}
可能有时候只有file对象,没有uri,可通过以下方法获取 其uri:
因Android 7.0 行为变更,通过FileProvider在应用间共享文件,所以要准备以下工作:
1:在res层新建xml的层(若有则不需):右键res-》Folder-》-》XML Resources Folder-》Finnish, 然后在xml层新建file_paths.xml,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
<!--path:代表该目录里的所有文件-->
<root-path
name="root"
path="." />
<cache-path
name="image_cache"
path="." />
</paths>
</resources>
2:在配置清单文件AndroidManifest.xml 的 application 里添加如下代码:
<!--provider的参数:
name:指向提供者所适应的类
authorities:项目包名.xxx; xxx只能小写否则运行时抛出异常
exported:这个提供者是否开放给外部app
grantUriPermissions:是否允许获取参数resource这个文件的权限
meta-data里的参数resource:配置需要访问哪些目录,也就是刚才的file_paths文件-->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.gx.picture.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
准备完后,就可以用以下代码用 FileProvider 来获取 conten://URI 类型的uri了:
//参数1 为content,参数2 为AndroidManifest.xml的provider里的authorities值,参数3 为 file 实例(该文件的file实例)
Uri uri=FileProvider.getUriForFile(MainActivity.this,"com.gx.picture.fileprovider",file);
/**
ps:奇怪的是Android 7 以下的,若 uri用 Uri imageUri=Uri.fromFile(cameraFile) 来获取,
在拍照后 无法获取拍照后的照片,即不执行onActivityResult方法,也不报错,
所以, 不管哪个版本的Android 都用 FileProvider 来获取 uri!!
*/