外部存储、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 }
手机外部存储.java

 

以上是关于外部存储、WRITE_EXTERNAL_STORAGE权限与maxSdkVersion属性的使用的主要内容,如果未能解决你的问题,请参考以下文章

Android数据存储(External Storage,外部存储)

Android数据存储(External Storage,外部存储)

内部存储器与外部存储器的区别

Android 中内部存储和外部存储的理解与应用

手机内部存储外部存储

内部存储到外部存储