关于Android读取SD卡存储的动态申请

news/2024/11/25 12:32:02/

关于Android读取SD卡存储的动态申请

  • 介绍
  • Android的目录结构
  • 数据的主要存储方式
  • 疑惑
    • 原来的代码:MainActivity.java
    • 修改后代码:

介绍

这篇文章主要关于我学习SD卡的动态获取权限时的一些问题。

Android的目录结构

参考自解析Android内部存储、外部存储的区别
图:目录结构
以我的手机为例,可以看到:
手机目录
与adb shell的ls命令相结合:
shell ls命令
可见,一般的手机用户(即非程序员用户)在手机的文件管理所能看到、操纵的文件都是手机的/storage/emulated/0目录下文件。

数据的主要存储方式

疯狂Android讲义–第四版中,主要提到的几种存储方式中:

  • 使用数据文件夹。即内存储
    • 使用SharedPreferences与Editor
      数据总保持在/data/data/< package name>/shared_prefs中
    • 使用openFileOutput和openFileInput
      数据总保持在/data/data/< package name>/files中
  • 读取SD卡上文件
    数据总保存在/storage/emulated/0目录下。
  • SQLite数据库
    嗯,存储的位置大概是比较随意。
    而这篇文章主要是关于SD卡的

疑惑

在学习教科书时,我发现课本的8.2.2节中,用Genymotion模拟器(google nexus 5,API 23)可以基本还原实验效果,但用我本人的真机(红米k30)以及Android Studio(Pixel_XL_API_30)自带的就不行了。
同时每次访问SD卡,都要来个:
在这里插入图片描述
你说这谁顶得住啊?
我搜了一下,说什么Android 6.0+需要动态申请。尤其是我发现,平时的文件也是放在所谓的SD卡目录下的,为什么其他应用就不用说什么动态申请?

原来的代码:MainActivity.java

package com.example.android.filetest;import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;/*** Description:<br>* 网站: <a href="http://www.crazyit.org">疯狂Java联盟</a><br>* Copyright (C), 2001-2020, Yeeku.H.Lee<br>* This program is protected by copyright laws.<br>* Program Name:<br>* Date:<br>** @author Yeeku.H.Lee kongyeeku@163.com<br>* @version 1.0*/
public class MainActivity extends Activity {private static final String FILE_NAME = "/crazy.bin";private EditText edit1;private TextView edit2;File f1;File f2;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 获取两个按钮Button read = findViewById(R.id.read);Button write = findViewById(R.id.write);// 获取两个文本框edit1 = findViewById(R.id.edit1);edit2 = findViewById(R.id.edit2);// 为write按钮绑定事件监听器write.setOnClickListener(view ->// 运行时请求获取写入SD卡的权限requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0x123)); // ①read.setOnClickListener(view ->requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0x456));}private String read() {
//        for (int i = 0; i < 10; i++) {
//            System.out.println(f2.canRead() + ", " + f2.canWrite());
//        }// 如果手机插入了SD卡,而且应用程序具有访问SD卡的权限if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {System.out.println(Environment.getExternalStorageState());// 获取SD卡对应的存储目录File sdCardDir = Environment.getExternalStorageDirectory();try (// 获取指定文件对应的输入流FileInputStream fis = new FileInputStream(sdCardDir.getCanonicalPath() + FILE_NAME);// 将指定输入流包装成BufferedReaderBufferedReader br = new BufferedReader(new InputStreamReader(fis))) {StringBuilder sb = new StringBuilder();String line = null;// 循环读取文件内容while ((line = br.readLine()) != null) {sb.append(line);}return sb.toString();} catch (IOException e) {e.printStackTrace();}}return null;}private void write(String content) {// 获取SD卡的目录File sdCardDir = Environment.getExternalStorageDirectory();try {System.out.println(sdCardDir.getCanonicalPath() + FILE_NAME);File targetFile = new File(sdCardDir.getCanonicalPath() + FILE_NAME);System.out.println("file is exist: " + targetFile.exists());// 以指定文件创建 RandomAccessFile对象RandomAccessFile raf = new RandomAccessFile(targetFile, "rw");raf.seek(targetFile.length());// 将文件记录指针移动到最后// 输出文件内容raf.write(content.getBytes());// 关闭RandomAccessFileraf.close();} catch (IOException e) {e.printStackTrace();}}@Overridepublic void onRequestPermissionsResult(int requestCode,String[] permissions, int[] grantResults) {if (requestCode == 0x123) {// 如果用户同意授权访问if (grantResults != null && grantResults[0] ==PackageManager.PERMISSION_GRANTED) {write(edit1.getText().toString());edit1.setText("");} else {// 提示用户必须允许写入SD卡的权限Toast.makeText(this, R.string.writesd_tip, Toast.LENGTH_LONG).show();}}if (requestCode == 0x456) {// 如果用户同意授权访问if (grantResults != null && grantResults[0] ==PackageManager.PERMISSION_GRANTED) {// 读取指定文件中的内容,并显示出来edit2.setText(read());} else {// 提示用户必须允许写入SD卡的权限Toast.makeText(this, R.string.writesd_tip, Toast.LENGTH_LONG).show();}}}
}

我觉得说可能是教材没说,就找了找,最终找了个参考:Android无法在SD卡写入文件(Android6.0+需要动态申请
解决了。

修改后代码:

package com.example.android.sdtest_my_1;import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;/*** Description:<br>* 网站: <a href="http://www.crazyit.org">疯狂Java联盟</a><br>* Copyright (C), 2001-2020, Yeeku.H.Lee<br>* This program is protected by copyright laws.<br>* Program Name:<br>* Date:<br>** @author Yeeku.H.Lee kongyeeku@163.com<br>* @version 1.0*/
public class MainActivity extends Activity {private static final String FILE_NAME = "/crazy.bin";private EditText edit1;private TextView edit2;File f1;File f2;//动态申请sd卡读写权限private static final int REQUEST_EXTERNAL_STORAGE = 1;private static String[] PERMISSIONS_STORAGE = {"android.permission.READ_EXTERNAL_STORAGE","android.permission.WRITE_EXTERNAL_STORAGE" };public static void verifyStoragePermissions(Activity activity) {try {//检测是否有写的权限int permission = ActivityCompat.checkSelfPermission(activity,"android.permission.WRITE_EXTERNAL_STORAGE");if (permission != PackageManager.PERMISSION_GRANTED) {// 没有写的权限,去申请写的权限,会弹出对话框ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE,REQUEST_EXTERNAL_STORAGE);}} catch (Exception e) {e.printStackTrace();}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 获取两个按钮Button read = findViewById(R.id.read);Button write = findViewById(R.id.write);// 获取两个文本框edit1 = findViewById(R.id.edit1);edit2 = findViewById(R.id.edit2);// 为write按钮绑定事件监听器write.setOnClickListener(view ->write());read.setOnClickListener(view ->read());verifyStoragePermissions(this);}private void read() {
//        for (int i = 0; i < 10; i++) {
//            System.out.println(f2.canRead() + ", " + f2.canWrite());
//        }// 如果手机插入了SD卡,而且应用程序具有访问SD卡的权限if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {System.out.println(Environment.getExternalStorageState());// 获取SD卡对应的存储目录File sdCardDir = Environment.getExternalStorageDirectory();try (// 获取指定文件对应的输入流FileInputStream fis = new FileInputStream(sdCardDir.getCanonicalPath() + FILE_NAME);// 将指定输入流包装成BufferedReaderBufferedReader br = new BufferedReader(new InputStreamReader(fis))) {StringBuilder sb = new StringBuilder();String line = null;// 循环读取文件内容while ((line = br.readLine()) != null) {sb.append(line);}edit2.setText(sb.toString());} catch (IOException e) {e.printStackTrace();}} else {edit2.setText(null);}}private void write() {String content = edit1.getText().toString();edit1.setText("");// 获取SD卡的目录File sdCardDir = Environment.getExternalStorageDirectory();try {System.out.println(sdCardDir.getCanonicalPath() + FILE_NAME);   // /storage/emulated/0/crazy.binFile targetFile = new File(sdCardDir.getCanonicalPath() + FILE_NAME);System.out.println("file is exist: " + targetFile.exists());// 以指定文件创建 RandomAccessFile对象RandomAccessFile raf = new RandomAccessFile(targetFile, "rw");raf.seek(targetFile.length());// 将文件记录指针移动到最后// 输出文件内容raf.write(content.getBytes());// 关闭RandomAccessFileraf.close();System.out.println("ok, writedc");} catch (IOException e) {e.printStackTrace();}}}

一次申请,永久ok……吧。

作者:Andrew Detmer(当然是假名了。)
原文链接


http://www.ppmy.cn/news/256410.html

相关文章

SD卡及SDIO协议简介

1、SD卡分类 STM32F4里&#xff0c;只支持SD 2.0协议&#xff0c;SD和SDHC属于这个范畴&#xff0c;SDXC是4.0协议&#xff0c;所以不支持&#xff1b;另外SDHC卡&#xff0c;有些数据块大小是512&#xff0c;有的是1024&#xff0c;STM32F4只支持读取512大小的&#xff0c;意…

STM32完成SD卡的数据写入

文章目录 一、SD卡模块简介二、读取SD卡三、总结四、参考 一、SD卡模块简介 简介 SD存储卡是一种基于半导体快闪记忆器的新一代记忆设备&#xff0c;由于它体积小、数据传输速度快、可热插拔等优良的特性&#xff0c;被广泛地于便携式装置上使用&#xff0c;例如数码相机、平板…

龙芯2K1000实战开发-kernel 开发

文章目录 概要整体架构流程技术名词解释技术细节小结概要 提示:这里可以添加技术概要 例如: 本文主要解释龙芯2K1000的内核开发。 整体架构流程 提示:这里可以添加技术整体架构 1.从 ftp 上下载的 Kernel 源码一般都会有一个 mymake 的脚本,编译和配置可以 直接借用此…

如何使用 Git

Git 是一种分布式版本控制系统&#xff0c;它可以记录文件的变化历史&#xff0c;并且可以在不同的分支上进行开发。在软件开发中&#xff0c;Git 是一个必不可少的工具。本文将介绍如何使用 Git。 安装 Git 首先&#xff0c;你需要在你的电脑上安装 Git。你可以在 Git 的官网…

DETR模型转RKNN

目录 1.前言 2.准备工作 3.开始转模型 4.测试代码 5.不想转&#xff0c;直接用也可以&#xff0c;转好的给你&#xff0c;请关注评论一下 1.前言 RKNN出最新版本了&#xff0c;测试了一下&#xff0c;rk在transformer方面做了很多的工作&#xff0c;至少之前不能转的模型&am…

【面试宝典】优秀求职者的必备技能-如何回答“小伙子,请做一下自我介绍?”

前言 我是沐风晓月,今天起,我的付费专栏《面试宝典》上线了,此专栏由互联网老辛,IT民工金鱼哥,漂流客,极客运维之家,逃离广寒宫的兔子,等多位大佬加持,有以下几个优势: 最贴近面试市场,都是大佬们的学员或者公司的最新面试题 最详细的面试方法,近千名学员面试复盘…

Android AIDL Callback的使用(配源码)

零、示例说明 本示例&#xff0c;完成的功能是&#xff1a;客户端向服务端注册一个回调&#xff0c;服务端是一个商店shop&#xff0c;当商店里的产品 Product 有变化时&#xff0c;调用回调向通知客户端&#xff0c;什么商品更新了。 一、完整源代码 完整源码链接: https:/…

Freeswitch学习笔记(一):Sip协议

目录 1.基本概念 1.1.名词概念 1.2.SIP的基本概念和相关元素 1.3.SIP协议的基本方法和头域简介