Scoped storage

文件存储介绍了内部存储和外部存储相关的内容。因为外部存储容易读写,所以在手机中经常看到很多“乱七八糟”的文件或文件夹,这些就是应用肆意创建的。

Android Q(10)开始添加了scoped storage的功能,更好的限制了应用访问外部存储。

先见个例子,下面代码运行在Android Q上会有什么现象呢:

AndroidManifest.xml中权限声明:

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

执行代码:

File[] externalFiles = context.getExternalFilesDirs( null );
for (File file : externalFiles) {
try {
File fileA = new File( file, "aaaa.txt" );
FileOutputStream fosA = new FileOutputStream( fileA );
fosA.close(); File fileB = new File( file.getParentFile().getParentFile().getParentFile().getParentFile(), "bbbb.txt" );
Log.d( TAG, "fileA="+fileA+";\nfileB="+fileB);
FileOutputStream fosB = new FileOutputStream( fileB );
fosB.close();
} catch (IOException e) {
Log.d( TAG, "exception: "+e.getMessage() );
e.printStackTrace();
}
}

执行的结果:

log的结果如下,实际与log是符合的。上述代码在四个 位置各创建一个文件,2个创建成功了2个fail了。/storage/emulated/0/和/storage/3B80-111D/下创建失败,提示权限问题。

2019-12-13 10:52:43.541 3973-3973/com.flx.testfilestorage D/flx_storage: fileA=/storage/emulated/0/Android/data/com.flx.testfilestorage/files/aaaa.txt;
fileB=/storage/emulated/0/bbbb.txt
2019-12-13 10:52:43.543 3973-3973/com.flx.testfilestorage D/flx_storage: exception: /storage/emulated/0/bbbb.txt: open failed: EACCES (Permission denied)
2019-12-13 10:52:43.554 3973-3973/com.flx.testfilestorage D/flx_storage: fileA=/storage/3B80-111D/Android/data/com.flx.testfilestorage/files/aaaa.txt;
fileB=/storage/3B80-111D/bbbb.txt
2019-12-13 10:52:43.556 3973-3973/com.flx.testfilestorage D/flx_storage: exception: /storage/3B80-111D/bbbb.txt: open failed: EACCES (Permission denied)

  

scoped storage在Android 10及更高版本默认开启。若之前的应用不满足这一功能,而运行在Android 10上 则需要将下面的属性设置成true,  关闭这一功能

<application android:requestLegacyExternalStorage="true" ... > 

上述代码修改后就能执行完成了。

注:后续版本可能强制要求开启scoped storage功能,上述关闭属性方法可能只是一个过渡。

以前的读写外部存储的权限:READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE。只要设置了这个就能够很容易的读写外部存储上的文件。

当scoped storage功能添加后,对权限和路径 具体有如下表格:

File location Permissions needed Method of accessing (*) Files removed when app uninstalled?
App-specific directory None getExternalFilesDir() Yes
Media collections
(photos, videos, audio)
READ_EXTERNAL_STORAGE
only when
accessing other apps' files
MediaStore No
Downloads
(documents and
e-books)
None Storage Access Framework
(loads system's file picker)
No

从上表中看到,只是访问其他应用的媒体文件 才需要READ_EXTERNAL_STORAGE权限,其他访问方式都不需要任何权限。(Storage Access Framework不了解可以点击链接 了解下)

开启scoped storage后,访问自身应用创建的文件都不需要任何权限(不管文件时创建在内部存储还是外部存储中)。而访问其他应用创建的文件,需要满足

1.需要READ_EXTERNAL_STORAGE权限;

2.该文件需要在下列某个媒体集合中:

  照片:存储在 MediaStore.Images 中。(image/*)
  视频:存储在 MediaStore.Video 中。(video/*)
  音乐文件:存储在 MediaStore.Audio 中。(audio/*)

为了访问另一应用创建的文件(包括“downloads”目录下的文件),您的应用必须使用存储访问框架(Storage Access Framework),用户可以通过该框架选择特定文件。

注意:使用scoped storage的应用无法直接访问类似 sdcard/DCIM/IMG1024.JPG 的路径。 要访问此类文件,必须使用MediaStore,并调用openFile()之类的方法。

scoped storage还添加了媒体相关数据限制

除非您的应用已获得 ACCESS_MEDIA_LOCATION 权限,否则图片文件中的 Exif 元数据会被删除。
MediaStore.Files 表已经过滤,仅显示照片、视频和音频文件。例如,该表格不会再显示 PDF 文件。(下面媒体文件部分也说到的)

媒体文件

MediaStore提供api接口 来访问下面定义良好的的媒体文件:

照片:存储在 MediaStore.Images(image/*) 中。
视频:存储在 MediaStore.Video(video/*) 中。
音频:存储在 MediaStore.Audio(audio/*) 中。

MediaStore.Files包含了所有media类型的文件集合。如果使用了scoped storage,则 MediaStore.Files仅仅包含上面3个类型(Images,Video,Audio)。

访问媒体文件

加载媒体文件,调用ContentResolver的方法:

  • 单个媒体文件,调用openFileDescriptor()。
  • 单个媒体文件的缩略图,调用loadThumbnail()。
  • 获取媒体文件集合,调用query()。

如下面一段代码 已Images为例,手机中只有拍摄的两张图片。

     ContentResolver contentResolver = this.getContentResolver();
Uri imgUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
Uri firstImgUri = null;
Cursor cursor = contentResolver.query( imgUri, null, null, null );
if (cursor != null && cursor.getCount() > 0) {
cursor.moveToFirst();
firstImgUri = Uri.fromFile( new File( cursor.getString( cursor.getColumnIndex( MediaStore.Images.Media.DATA ) ) ) );
do {
Log.d( TAG, "img cursor data=" + cursor.getString( cursor.getColumnIndex( MediaStore.Images.Media.DATA ) )
+";\nimg cursor type=" + cursor.getString( cursor.getColumnIndex( MediaStore.Images.Media.MIME_TYPE ) ));
} while (cursor.moveToNext());
}
Log.d( TAG, "firstImgUri="+firstImgUri );
try {
ParcelFileDescriptor parcelFileDescriptor = contentResolver.openFileDescriptor( firstImgUri, "r" ); if (Build.VERSION.SDK_INT >= 29) {
Bitmap bitmap = contentResolver.loadThumbnail( firstImgUri, new Size( 200,200 ), null );
}
} catch (Exception e) {
Log.d( TAG, "exception: "+e.getMessage() );
}

执行后的结果:

2019-01-02 11:31:00.937 15513-15513/com.flx.testfilestorage D/flx_storage: img cursor data=/storage/emulated/0/DCIM/Camera/IMG_20190102_031552_3.jpg;
img cursor type=image/jpeg
2019-01-02 11:31:00.937 15513-15513/com.flx.testfilestorage D/flx_storage: img cursor data=/storage/emulated/0/DCIM/Camera/IMG_20190102_031909_3.jpg;
img cursor type=image/jpeg
2019-01-02 11:31:00.938 15513-15513/com.flx.testfilestorage D/flx_storage: firstImgUri=file:///storage/emulated/0/DCIM/Camera/IMG_20190102_031552_3.jpg

  

IS_PENDING独占

Android 10以后,当写入磁盘时 应用可以通过IS_PENDING标志实现对媒体文件的独占访问。

如:

     ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, "TEST.jpg");
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.Images.Media.IS_PENDING, 1); Uri collection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
Uri item = contentResolver.insert(collection, values); try (ParcelFileDescriptor pfd = contentResolver.openFileDescriptor(item, "w", null)) {
Parcel out = Parcel.obtain();
pfd.writeToParcel( out, Parcelable.PARCELABLE_WRITE_RETURN_VALUE );
} catch (IOException e) {
Log.d( TAG, "e:"+e.getMessage() );
} values.clear();
values.put(MediaStore.Images.Media.IS_PENDING, 0);//释放,使其他应用可以访问
contentResolver.update(item, values, null, null);

Android_存储之scoped storage&媒体文件的更多相关文章

  1. Android_存储之文件存储

    前面几篇随笔 讲到的关于存储的,SharedPreferences.Room.数据库等 最终都是以文件形式 存储到手机上的(除特殊的存储于手机内存的:如Room可以创建内存数据库). 这些存储方式,A ...

  2. 利用HTML5开发Android(7)---HTML5本地存储之Database Storage

    在上一篇<HTML5本地存储之Web Storage篇>中,简单介绍了如何利用localStorage实现本地存储:实际上,除了sessionStorage和localStorage外,H ...

  3. HTML5分析实战Web存储机制(Web Storage)

    Web Storage它是Key-Value在持久性数据存储的形式.Web Storage为了克服cookie把所引起的一些限制.当数据需要严格格控制client准时,没有必要不断地发回数据serve ...

  4. Django (七) token&静态文件&媒体文件

    token&静态文件&媒体文件 1. token 1. 会话技术 2. 服务端会话技术 3. 它实际上就是手动实现的session 4. 实现token 4.1 在models.py中 ...

  5. Cluster基础(五):配置tracker、配置storage、文件测试及web访问

    一.配置tracker 目标: FastDFS是一个分布式文件系统,主要的服务器角色有Tracker和Storage.本例安装一台Tracker,实现以下功能: 接受客户端的访问 检索存储节点,为客户 ...

  6. Android_存储访问框架SAF

    概念 存储访问框架---Storage Access Framework (SAF),这是在Android4.4(API level 19)之后引入的. 借助 SAF,用户可轻松在其所有首选文档存储提 ...

  7. 对象存储 COS 全新集成媒体处理功能

    根据<2020年中国网络视听发展研究报告>,截至2020年6月,我国网络视听用户规模达9.01亿,网民使用率95.8%.这表明视频行业已经成为新的流量洼地,而抖音.快手等视频平台的崛起也让 ...

  8. 【译】客户端存储(Client-Side Storage)

    本文转载自:众成翻译译者:文蔺链接:http://www.zcfy.cc/article/660原文:http://www.html5rocks.com/en/tutorials/offline/st ...

  9. [译]:Orchard入门——媒体文件的添加与管理

    原文链接:Adding and Managing Media Content 注:此文内容相对较老,实际操作指导性不强,仅适合做研究 当你利用富文本编辑器上传图片时(或者使用XML-RPC客户端,例如 ...

随机推荐

  1. STL部分学习总结

    一.map/multimap map/multimap映射容器的元素数据是由一个Key和一个Value成的,key与映照value之间具有一一映照的关系. map/multimap容器的数据结构也采用 ...

  2. 图论--网络流--最大流 洛谷P4722(hlpp)

    题目描述 给定 nn 个点,mm 条有向边,给定每条边的容量,求从点 ss 到点 tt 的最大流. 输入格式 第一行包含四个正整数nn.mm.ss.tt,用空格分隔,分别表示点的个数.有向边的个数.源 ...

  3. css属性、样式、边框、选择器

    CSS 层叠样式表 (Cascading Style Sheets,缩写为 CSS),是一种 样式表 语言, 用来描述 HTML或 XML(包括如 SVG.MathML.XHTML 之类的 XML 分 ...

  4. 从零搭建分布式文件系统MinIO比FastDFS要更合适

    前两天跟大家分享了一篇关于如何利用FastDFS组件来自建分布式文件系统的文章,有兴趣的朋友可以阅读下<用asp.net core结合fastdfs打造分布式文件存储系统>.通过留言发现大 ...

  5. IoTClientTool自动升级更新

    IoTClientTool是什么 IoTClientTool是什么,IoTClientTool是IoTClient开源组件的可视化操的作实现.方便对plc设备和ModBusRtu.BACnet.串口等 ...

  6. NetCore项目实战篇05---添加Ocelot网关并集成identity server4认证

    今天来给我们的项目增加API网关,使用Ocelot. 它是系统暴露在外部的一个访问入口,这个有点像代理访问的家伙,就像一个公司的门卫承担着寻址.限制进入.安全检查.位置引导.等等功能.同时我们还要在网 ...

  7. 12_JavaScript基础入门(2)

    运算符 运算符(Operators,也翻译为操作符),是发起运算的最简单形式. 运算符的分类见仁见智,我们的课程对运算符进行如下分类: 数学运算符(Arithmetic operators)      ...

  8. python路径操作新标准:pathlib 模块

    之前如果要使用 python 操作文件路径,我总是会条件反射导入 os.path. 而现在,我会更加喜欢用新式的 pathlib, 虽然用得还是没有 os.path 熟练,但是以后会坚持使用. pat ...

  9. Python:日薪工资计算

    劳动者离职,当天要结清工资,实际操作是当天算清,三日内结清.有的公司省人力和吃利息,统一计算,统一下月月底发放. 有时要验算下离职工资,用Python操作一番,输入计时天数.请假小时.加班小时.基本工 ...

  10. Mybatis学习笔记汇总(包括源码和jar包)

    博客整理 Mybatis学习笔记(一)--对原生jdbc中问题的总结 Mybatis学习笔记(二)--Mybatis框架 Mybatis学习笔记(三)--入门程序 MyBatis学习笔记(四)--入门 ...