外部存储、WRITE_EXTERNAL_STORAGE权限与maxSdkVersion属性的使用
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了外部存储、WRITE_EXTERNAL_STORAGE权限与maxSdkVersion属性的使用相关的知识,希望对你有一定的参考价值。
参考技术A最近在项目中发现READ_EXTERNAL_STORAGE配置了maxSdkVersion 属性,于是决定对maxSdkVersion属性研究一番。研究过程中涉及好几个知识点:文件存储结构、外部存储权限、动态权限申请等。
android 的文件存储分为:Internal file storage 和 External file storage。
如果您希望与其他应用共享文件,可以使用 FileProvider。
外部存储空间中的文件并非始终都能访问到,因其存储于外部存储空间,有可能是从内部存储中分配出来的虚拟外部存储,有可能是SD卡存储。还有可能会移除 SD卡,因此在访问之前,您应检查外部存储目录及您尝试访问的文件是否可用。
市场上有些设备将内部存储分出虚拟外部存储,同时还会提供 SD 卡插槽。这意味着这些设备会有两个不同的外部存储目录,因此在将“私有”文件写入外部存储时,需要选择使用哪个目录。
Android 包含以下访问外部存储中的文件的权限:
从 Android 4.4(API 19)开始,在 “应用特定的目录(“私有文件目录”)” 中读取或写入文件不再需要任何与存储相关的权限。
因此,如果您的应用支持 Android 4.3(API 18)及更低版本, 并且您只想访问应用特定的目录(“私有文件目录”) ,则可以添加 maxSdkVersion 属性,声明仅在较低版本的 Android 上请求权限: (这里可能有坑,会和Android6.0权限有点小问题,慎用。)
具体说明:
最后关于权限的结论:
"存储权限最好还是都在清单中配置上,而且maxSdkVersion属性要慎用。"
可能有人会问,我这篇文章说了这么多,好像是都在说废话,还得出了一个废话结论,其实我是带着下面的疑问和设想来研究本文的。
以下几点是我对外部存储权限的理解,本文旨在理清其中一些隐藏细节。
上面是我的理解,欢迎大家指出我理解不对的地方~
参考链接:
https://developer.android.google.cn/guide/topics/data/data-storage
https://developer.android.google.cn/training/data-storage/files/external
数据存储——手机外部文件存储
一.特点
1.把文件存储在手机外部存储空间(SD卡)里
2.存储的是任意类型的文件
3.使用IO输入输出流操作文件
4.文件路径
1-SD卡根目录/Android/data/包名/files/[ 文件类型],应用卸载后,数据同时被删除;
2-SD卡根目录/,应用卸载之后,数据不会被同时删除。
5.需要声明权限
1-android.permission.WRITE_EXTERNAL_STORAGE,写入文件;
2-MOUNT_UNMOUNT_FILESYSTEMS,创建和删除文件。
二.API
1.Environment
1-SD卡的工具类
2-getExternalStorageState() 得到SD卡的状态,Environment.MEDIA_MOUNTED 挂载状态。
3-getExternalStorageDirectory( ) 得到SD卡的根目录File实例
2.context.getExternalFilesDir(type) 得到带包名的外部存储路径
type 文件类型目录:
1-null 表示不创建类型子目录
2-会根据类型创建相应的子目录
手机外部内存存储代码展示:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:tools="http://schemas.android.com/tools" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent" 6 android:paddingBottom="@dimen/activity_vertical_margin" 7 android:paddingLeft="@dimen/activity_horizontal_margin" 8 android:paddingRight="@dimen/activity_horizontal_margin" 9 android:paddingTop="@dimen/activity_vertical_margin" 10 tools:context="com.hanqi.testapp3.MainActivity" 11 android:orientation="vertical"> 12 13 <EditText 14 android:layout_width="match_parent" 15 android:layout_height="wrap_content" 16 android:hint="输入..." 17 android:id="@+id/et_1"/> 18 19 <Button 20 android:layout_width="match_parent" 21 android:layout_height="wrap_content" 22 android:text="写入外部存储文件" 23 android:onClick="bt6_OnClick"/> 24 25 <Button 26 android:layout_width="match_parent" 27 android:layout_height="wrap_content" 28 android:text="读取外部存储文件" 29 android:onClick="bt7_OnClick"/> 30 31 32 </LinearLayout>
1 package com.hanqi.testapp3; 2 3 import android.content.SharedPreferences; 4 import android.content.res.AssetManager; 5 import android.graphics.Bitmap; 6 import android.graphics.BitmapFactory; 7 import android.os.Environment; 8 import android.support.v7.app.AppCompatActivity; 9 import android.os.Bundle; 10 import android.text.BidiFormatter; 11 import android.view.View; 12 import android.widget.EditText; 13 import android.widget.ImageView; 14 import android.widget.TextView; 15 import android.widget.Toast; 16 17 import java.io.File; 18 import java.io.FileInputStream; 19 import java.io.FileOutputStream; 20 import java.io.InputStream; 21 import java.io.PrintStream; 22 23 24 public class MainActivity extends AppCompatActivity { 25 26 TextView tv_1; 27 EditText et_1; 28 ImageView iv_1; 29 30 @Override 31 protected void onCreate(Bundle savedInstanceState) { 32 super.onCreate(savedInstanceState); 33 setContentView(R.layout.activity_main); 34 35 et_1=(EditText)findViewById(R.id.et_1); 36 37 } 38 39 40 //写入外部存储文件 41 public void bt6_OnClick(View v) 42 { 43 //1.判断SD卡是否挂载 44 45 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) 46 { 47 //文本框内容 48 String str=et_1.getText().toString(); 49 50 try { 51 //写入 52 //1.构造输出流 53 //1)得到文件路径 54 55 //得到SD卡根目录 56 //String path=Environment.getExternalStorageDirectory().getCanonicalPath(); 57 58 //得到包名对应的目录 59 String path=getExternalFilesDir("Music").getAbsolutePath(); 60 61 Toast.makeText(MainActivity.this, "path="+path, Toast.LENGTH_LONG).show(); 62 //2)构造 63 FileOutputStream fos = new FileOutputStream(path+"/test.txt"); 64 65 PrintStream ps=new PrintStream(fos); 66 67 ps.print(str); 68 69 ps.close(); 70 fos.close(); 71 72 Toast.makeText(MainActivity.this, "写入外部文件成功", Toast.LENGTH_SHORT).show(); 73 } 74 catch (Exception e) 75 { 76 e.printStackTrace(); 77 Toast.makeText(MainActivity.this, "存储文件出错", Toast.LENGTH_SHORT).show(); 78 } 79 } 80 else 81 { 82 Toast.makeText(MainActivity.this, "SD卡没有挂载", Toast.LENGTH_SHORT).show(); 83 } 84 } 85 86 public void bt7_OnClick(View v) 87 { 88 //1.判断SD卡是否挂载 89 90 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) 91 { 92 try { 93 94 String path = getExternalFilesDir("Music").getCanonicalPath() + "/test.txt"; 95 96 FileInputStream fis=new FileInputStream(path); 97 98 byte [] b=new byte[1024]; 99 int i=0; 100 101 String str=""; 102 103 while ((i=fis.read(b))>0) 104 { 105 str+=new String(b,0,i); 106 } 107 108 fis.close(); 109 110 Toast.makeText(MainActivity.this, "文件内容="+str, Toast.LENGTH_SHORT).show(); 111 } 112 catch (Exception e) 113 { 114 115 Toast.makeText(MainActivity.this, "读取外部文件失败", Toast.LENGTH_SHORT).show(); 116 } 117 } 118 else 119 { 120 Toast.makeText(MainActivity.this, "SD卡没有挂载", Toast.LENGTH_SHORT).show(); 121 } 122 } 123 }
以上是关于外部存储、WRITE_EXTERNAL_STORAGE权限与maxSdkVersion属性的使用的主要内容,如果未能解决你的问题,请参考以下文章
Android数据存储(External Storage,外部存储)