Android 保存/读取本地SD卡文件(兼容Android 13)
1.manifeast文件
(1)app权限
(2)application配置
(3)组件配置
注意:Android 12以上,组件创建会自动生成以下属性
android:exported="true"
表示”是否支持其它应用调用当前组件”
如果不添加改属性,会报错。
2.动态申请文件存储权限
说明,Android的权限根据版本号分为三种
Android6.0之前
Android6.0-Android 10
Android 11以后
其中,6.0之前不需要动态申请权限,只需要在manifest文件中申请即可。从6.0之后,app需要动态申请权限,即弹框询问用户,是否给用户授权。Android 11以后,对权限的控制进一步收紧,很多的权限申请发生改变,例如,此前操作文件,只需要声明读写权限即可,但是现在划分了图片、音频、视频等等,并且操作普通文件的权限也变为MANAGE_EXTERNAL_STORAGE
代码如下:
private static final int REQUEST_EXTERNAL_STORAGE = 1;private static String[] PERMISSIONS_STORAGE = { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE};private boolean havePermission = false;
@Overrideprotected void onResume() { super.onResume(); checkPermission();}
private AlertDialog dialog;private void checkPermission() { //检查权限(NEED_PERMISSION)是否被授权 PackageManager.PERMISSION_GRANTED表示同意授权 if (Build.VERSION.SDK_INT >= 30) { if (!Environment.isExternalStorageManager()) { if (dialog != null) { dialog.dismiss(); dialog = null; } dialog = new AlertDialog.Builder(this) .setTitle("提示")//设置标题 .setMessage("请开启文件访问权限,否则无法正常使用本应用!") .setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int i) {dialog.dismiss(); } }) .setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) {dialog.dismiss();Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);startActivity(intent); } }).create(); dialog.show(); } else { havePermission = true; Log.i("swyLog", "Android 11以上,当前已有权限"); } } else { if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { //申请权限 if (dialog != null) { dialog.dismiss(); dialog = null; } dialog = new AlertDialog.Builder(this) .setTitle("提示")//设置标题 .setMessage("请开启文件访问权限,否则无法正常使用本应用!") .setPositiveButton("确定", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) { dialog.dismiss(); ActivityCompat.requestPermissions(BrowserActivity.this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);} }).create(); dialog.show(); } else { havePermission = true; Log.i("swyLog", "Android 6.0以上,11以下,当前已有权限"); } } else { havePermission = true; Log.i("swyLog", "Android 6.0以下,已获取权限"); } }}
@Overridepublic void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case REQUEST_EXTERNAL_STORAGE: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { havePermission = true; Toast.makeText(this, "授权成功!", Toast.LENGTH_SHORT).show(); } else { havePermission = false; Toast.makeText(this, "授权被拒绝!", Toast.LENGTH_SHORT).show(); } return; } }}
3.文件操作
(1)定义文件保存的路径及文件名
private String FILE_SAVE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/MobileReport/";private String FILE_NAME = "user.txt";
(2)保存文件
private void saveLoginAccount(String json) { if (TextUtils.isEmpty(json)) { return; } Log.i("swyLog", "saveLoginAccount called"); String value = encodeToString(json); Log.i("swyLog", "save 明文:" + json); Log.i("swyLog", "save 密文:" + value); File storage = new File(FILE_SAVE_PATH); if (!storage.exists()) { storage.mkdirs(); } File tmepfile = new File(storage.getPath()); if (!tmepfile.exists()) { tmepfile.mkdirs(); } File file = new File(tmepfile, FILE_NAME); if (file.exists()) { Log.i("swyLog", "删除原有文件"); file.delete(); } if (!file.exists()) { Log.i("swyLog", "文件删除成功"); try { file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } FileOutputStream fileOutputStream = null; try { fileOutputStream = new FileOutputStream(file); fileOutputStream.write(value.getBytes()); } catch (Exception e) { e.printStackTrace(); } finally { if (fileOutputStream != null) { try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } }}
(3)读取文件
private String uploadLoginAccount() { Log.i("swyLog", "uploadLoginAccount called"); InputStream inputStream = null; Reader reader = null; BufferedReader bufferedReader = null; try { File storage = new File(FILE_SAVE_PATH); if (!storage.exists()) { return ""; } File file = new File(storage, FILE_NAME); if (!file.exists()) { return ""; } inputStream = new FileInputStream(file); reader = new InputStreamReader(inputStream); bufferedReader = new BufferedReader(reader); StringBuilder result = new StringBuilder(); String temp; while ((temp = bufferedReader.readLine()) != null) { result.append(temp); } String value = decodeToString(result.toString()); Log.i("swyLog", "upload 密文:" + result); Log.i("swyLog", "upload 明文:" + value); return value; } catch (Exception e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (bufferedReader != null) { try { bufferedReader.close(); } catch (IOException e) { e.printStackTrace(); } } } return "";}
(4)删除文件
private void deleteLoginAccount() { Log.i("swyLog", "deleteLoginAccount called"); File storage = new File(FILE_SAVE_PATH); if (!storage.exists()) { storage.mkdirs(); } File tmepfile = new File(storage.getPath()); if (!tmepfile.exists()) { tmepfile.mkdirs(); } File file = new File(tmepfile, FILE_NAME); if (file.exists()) { try { Log.i("swyLog", "删除原有文件"); file.delete(); } catch (Exception e) { e.printStackTrace(); } } if (!file.exists()) { Log.i("swyLog", "文件删除成功"); }}
(5)base64 加解密方法
public static String encodeToString(String str) { try { return Base64.encodeToString(str.getBytes("UTF-8"), Base64.DEFAULT); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return "";}public static String decodeToString(String str) { try { return new String(Base64.decode(str.getBytes("UTF-8"), Base64.DEFAULT)); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return "";}
说明:我这里是从项目中复制的代码,作用是,将字符串加密之后,保存到sd卡种,加密的原因自然不言而喻,因为有些信息是不方便直接展示给用户看的。
来源地址:https://blog.csdn.net/weixin_53324308/article/details/129966403
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341