概述

在Android开发中,存储(Storage)的方式根据具体的需求不同而不同,例如数据对应用程序是私有的还是其他应用程序(和用户)可以访问的,以及保存数据需要多大的空间。

存储分类

主要的存储方式有以下几种(本文主要涉及前三种):

  1. Shared Preferences:以键值对( key-value pairs)的方式存储在程序内部;
  2. Internal Storage:将数据保存在设备内存中;
  3. External Storage:将公有数据保存在外部存储中(SD卡);
  4. SQLite Databases:保存结构化数据到私有数据库中;
  5. Network Connection:通过网络服务器,将数据存储在web上。

涉及知识点

涉及的知识点如下:

  1. SharedPreferences 共享目录接口,通过Context中的getSharedPreferences进行实例化。
  2. SharedPreferences.Editor 共享目录编辑器,需要以commit进行保存。
  3. FileOutputStream 文件输出流,用write方法将数据保存文件。
  4. FileInputStream 文件输入流,用于读取文件的内容,通过Context中的openFileInput进行实例化,用read方法进行读取内容。
  5. deleteFile Context中的方法,删除指定路径的文件
  6. Environment.getExternalStorageDirectory() 获取外部存储的根目录。
  7. Environment.getExternalStorageState() 获取外部存储卡的状态。
  8. File.separator 文件路径分割符,用斜杠(/)进行表示。
  9. BitmapFactory.decodeResource(getResources(), R.drawable.bg) 通过资源文件实例化对象。
  10. BitmapFactory.decodeFile(imgFile.getAbsolutePath() 通过具体文件的路径实例化对象。
  11. File 文件对象,mkdirs() 创建多层目录 mkdirs创建单个目录,exists() 判断文件或目录是否存在,createNewFile() 创建新文件。

Shared Preferences

此种方式,只能保存简单的数据类型如下图所示:

代码如下:

     /**
* SharedPreferences保存
* @param v
*/
public void sharedSave(View v){
String name=etName.getText().toString().trim();
String age=etAge.getText().toString().trim();
if(TextUtils.isEmpty(name)||TextUtils.isEmpty(age)){
return;
}
//构造一个编辑器----笔
SharedPreferences.Editor editor = sp.edit();
//数据的存储---只能存储简单的数据
editor.putString("name",name);
editor.putString("age",age);
//提交--保存
editor.commit();
//清空
etName.setText("");
etAge.setText("");
} /**
* SharedPreferences读取
*/
public void sharedRedo(View v){
String name=sp.getString("name","");
String age=sp.getString("age","");
etName.setText(name);
etAge.setText(age);
}

Internal Storage

将数据内容转换为字节的方式保存在文件中,如下图所示:

代码如下:

     /**
* 内部保存
* @param v
*/
public void internalSave(View v) {
String name = etName.getText().toString().trim();
String age = etAge.getText().toString().trim();
if (TextUtils.isEmpty(name) || TextUtils.isEmpty(age)) {
return;
} try {
String content = "这是我的姓名:" + name + "这是我的年龄:" + age;
FileOutputStream fos = openFileOutput(sname, MODE_PRIVATE);
fos.write(content.getBytes());
fos.close();
etName.setText("");
etAge.setText("");
} catch (IOException e) {
e.printStackTrace();
}
} /**
* 内部读取
* @param v
*/
public void internalRedo(View v) {
try {
FileInputStream fis = openFileInput(sname);
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
fis.close();
String content = new String(buffer);
Toast.makeText(this, content, Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
} /**
* 删除文件
* @param v
*/
public void internalDel(View v){
boolean del=deleteFile(sname);
if(del){
Toast.makeText(this, "删除成功", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this, "删除失败", Toast.LENGTH_SHORT).show();
}
}

External Storage

在外部存储中,需要在AndroidManifest.xml中配置相关的读写权限,如下所示:

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

保存在SD卡中,如下图所示:

代码如下:

     /**
* 外部存储
* @param v
*/
public void externalSave(View v) { try {
Log.i(TAG, "externalSave: 开始");
Bitmap img = BitmapFactory.decodeResource(getResources(), R.drawable.bg);
ByteArrayOutputStream bass = new ByteArrayOutputStream();
img.compress(Bitmap.CompressFormat.JPEG, 100, bass);
img.recycle();
Log.i(TAG, "externalSave: saveImg");
boolean saveOk = saveImg("dog.jpg", bass.toByteArray());
Log.i(TAG, "externalSave: saveImg:"+saveOk);
if (saveOk) {
Toast.makeText(this, "保存成功", Toast.LENGTH_SHORT).show();
}
bass.close();
Log.i(TAG, "externalSave: 结束");
} catch (IOException e) {
e.printStackTrace();
Log.i(TAG, "externalSave: 异常"+e.getMessage());
}
} /**
* 外部读取
* @param v
*/
public void externalRedo(View v) {
if (!isMounted()) {
return;
}
try {
Bitmap img = readImg("dog.jpg");
iv01.setImageBitmap(img);
} catch (Exception e) {
e.printStackTrace();
}
} private boolean saveImg(String fileName,byte[] data){
Log.i(TAG, "saveImg: 开始");
if(!isMounted()){
Log.i(TAG, "saveImg: 挂载失败");
return false;
}
Log.i(TAG, "saveImg: 路径:"+storedPath);
File dir=new File(storedPath);
if(!dir.exists()){
boolean f= dir.mkdirs();
if(f){
Log.i(TAG, "saveImg: 创建目录成功:"+storedPath);
}else{
Log.i(TAG, "saveImg: 创建目录失败:"+storedPath);
}
}
Log.i(TAG, "saveImg: 判断路径:ok");
try {
File file=new File(storedPath,fileName);
if(file.exists()){
Log.i(TAG, "saveImg: 判断文件:1");
file.delete();
}
Log.i(TAG, "saveImg: 判断文件:2");
file.createNewFile();
Log.i(TAG, "saveImg: 判断文件:ok");
FileOutputStream fos=new FileOutputStream(file);
fos.write(data);
fos.close();
return true;
} catch (IOException e) {
e.printStackTrace();
Log.i(TAG, "saveImg: 异常:"+e.getMessage());
return false;
}
} public Bitmap readImg(String fileName){
if(!isMounted()){
return null;
}
File imgFile=new File(storedPath,fileName);
if(imgFile.exists()){
return BitmapFactory.decodeFile(imgFile.getAbsolutePath());
}
return null;
} private boolean isMounted(){
String state=Environment.getExternalStorageState();
return state.equals(Environment.MEDIA_MOUNTED);
}

备注

在进行外部存储时,如果默认关闭了APP的存储空间权限,没有前往设置开启应用权限,即使manifest中正常注册权限,该APP仍让无法读写文件。调试日志如下:

-----------------------------------------------------------------------------------------------------------------------------------------------------------------

未开启App的存储权限
04-02 21:21:59.173 30863-30863/com.hex.demostorage I/DemoStorage: externalSave: 开始
04-02 21:21:59.407 30863-30863/com.hex.demostorage I/DemoStorage: externalSave: saveImg
04-02 21:21:59.408 30863-30863/com.hex.demostorage I/DemoStorage: saveImg: 开始
04-02 21:21:59.412 30863-30863/com.hex.demostorage I/DemoStorage: saveImg: 路径:/storage/emulated/0/hex/images
04-02 21:21:59.412 30863-30863/com.hex.demostorage I/DemoStorage: saveImg: 判断路径:ok
04-02 21:21:59.412 30863-30863/com.hex.demostorage I/DemoStorage: saveImg: 判断文件:2
04-02 21:21:59.414 30863-30863/com.hex.demostorage I/DemoStorage: saveImg: 异常:No such file or directory
04-02 21:21:59.414 30863-30863/com.hex.demostorage I/DemoStorage: externalSave: saveImg:false
04-02 21:21:59.414 30863-30863/com.hex.demostorage I/DemoStorage: externalSave: 结束
开启App的存储权限
04-02 21:22:48.519 31306-31306/com.hex.demostorage I/DemoStorage: externalSave: 开始
04-02 21:22:48.754 31306-31306/com.hex.demostorage I/DemoStorage: externalSave: saveImg
04-02 21:22:48.755 31306-31306/com.hex.demostorage I/DemoStorage: saveImg: 开始
04-02 21:22:48.759 31306-31306/com.hex.demostorage I/DemoStorage: saveImg: 路径:/storage/emulated/0/hex/images
04-02 21:22:48.760 31306-31306/com.hex.demostorage I/DemoStorage: saveImg: 判断路径:ok
04-02 21:22:48.760 31306-31306/com.hex.demostorage I/DemoStorage: saveImg: 判断文件:2
04-02 21:22:48.761 31306-31306/com.hex.demostorage I/DemoStorage: saveImg: 判断文件:ok
04-02 21:22:48.763 31306-31306/com.hex.demostorage I/DemoStorage: externalSave: saveImg:true
04-02 21:22:48.787 31306-31306/com.hex.demostorage I/DemoStorage: externalSave: 结束

-----------------------------------------------------------------------------------------------------------------------------------------------------------------

记录学习,记录成长!

一起学Android之Storage的更多相关文章

  1. Android开发学习之路-该怎么学Android(Service和Activity通信为例)

    在大部分地方,比如书本或者学校和培训机构,教学Android的方式都基本类似,就是告诉先上原理方法,然后对着代码讲一下. 但是,这往往不是一个很好的方法,为什么? ① 学生要掌握这个方法的用途,只能通 ...

  2. 菜鸟学Android编程——简单计算器《一》

    菜鸟瞎搞,高手莫进 本人菜鸟一枚,最近在学Android编程,网上看了一些视频教程,于是想着平时手机上的计算器应该很简单,自己何不尝试着做一个呢? 于是就冒冒失失的开撸了. 简单计算器嘛,功能当然很少 ...

  3. 学Android开发,入门语言java知识点

    学Android开发,入门语言java知识点 Android是一种以Linux为基础的开源码操作系统,主要使用于便携设备,而linux是用c语言和少量汇编语言写成的,如果你想研究Android,就去学 ...

  4. DoNet屌丝学Android(一)——Android开发准备工作 & No HelloWord & (真机)调试

    先乱扯淡一下吧,本人一.net屌丝,手持Android 4.2.2手机,Win7 x64本本,闲来无聊学习一下Android的开发,至于要开发啥玩意目前没有什么想法,就是想学学,搞不好是三分热度也有可 ...

  5. 从头学Android系列

    从头学Android系列 http://blog.csdn.net/worker90/article/category/888358

  6. 学Android开发 这19个开发工具助你顺风顺水

    学Android开发 这19个开发工具助你顺风顺水 要想快速开发一个Android应用,通常会用到很多工具,巧妙利用这些工具,能让我们的开发工作事半功倍,节省大量时间,下面大连Android开发培训小 ...

  7. 一步一步学android控件(之十五) —— DegitalClock & AnalogClock

    原本计划DigitalClock和AnalogClock单独各一篇来写,但是想想,两个控件的作用都一样,就和在一起写一篇了. DegitalClock和AnalogClock控件主要用于显示当前时间信 ...

  8. 一步一步学android控件(之十六)—— CheckBox

    根据使用场景不同,有时候使用系统默认的CheckBox样式就可以了,但是有时候就需要自定义CheckBox的样式.今天主要学习如何自定义CheckBox样式.在CheckBox状态改变时有时需要做一些 ...

  9. 【视频】零基础学Android开发:蓝牙聊天室APP(四)

    零基础学Android开发:蓝牙聊天室APP第四讲 4.1 ListView控件的使用 4.2 BaseAdapter具体解释 4.3 ListView分布与滚动事件 4.4 ListView事件监听 ...

随机推荐

  1. socket编程中客户端常用函数

    1 常用函数 1.1   connect() int connect(int sockfd, const struct sockaddr *servaddr, socklen_taddrlen); 客 ...

  2. POI处理Excel中各种日期格式问题

    前不久写过一篇随笔<EXCEL解析之终极方法WorkbookFactory>,提到使用WorkbookFactory来处理Excel文件数据,最近发现一个问题就是这个办法不能很好的处理各种 ...

  3. mysql中如何处理字符

    concat函数 使用方法: CONCAT(str1,str2,…) 返回结果为连接参数产生的字符串.如有任何一个参数为NULL ,则返回值为 NULL. 注意: 如果所有参数均为非二进制字符串,则结 ...

  4. SSM-Spring-16:Spring中一些名词解释

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- JoinPoint(连接点):所谓连接点是指那些被拦截到的点.在spring中,这些点指的是方法,因为spri ...

  5. 把一个机器上1天内新增的文件用rsync传送到另外一台机器

    我的shell很菜,只好用shell和php结合来做 1.查找新增的文件,构造rsync的参数,把结果写入到log中 find /data/bmob/test/teststorage/data/ -m ...

  6. kafka 三个配置文件

    kafka的配置分为 broker.producter.consumer三个不同的配置 一 BROKER 的全局配置   最为核心的三个配置 broker.id.log.dir.zookeeper.c ...

  7. 「CodeChef Dec13 REALSET」 Petya and Sequence 循环卷积

    题目大意: 传送门 T组询问. 每组给一个数组,询问该数组是否循环移位线性无关,输出YES或NO. 题解: LCA冬令营有讲……然而当时…… 并不知道如何计算一个数组是否循环移位线性无关……网上也没有 ...

  8. bzoj 4565 状压区间dp

    我还以为我状压很好...... 噗!!! 果然我区间很差... f[i][j][s]表示i~j段,合并后的状态为s所得的最大收益 枚举i,j,k,s. f[i][j][s<<1]=max( ...

  9. web版仿微信聊天界面|h5仿微信电脑端案例开发

    前几天开发了一款手机端h5仿微信聊天,人唯有不停学习才能进步,这段时间倒腾着整理了下之前项目,又重新在原先的那版基础上开发了一款仿微信聊天电脑端web版本,聊天页面又重新优化了多图预览.视频播放,右键 ...

  10. WebGL three.js学习笔记 使用粒子系统模拟时空隧道(虫洞)

    WebGL three.js学习笔记 使用粒子系统模拟时空隧道 本例的运行结果如图: 时空隧道demo演示 Demo地址:https://nsytsqdtn.github.io/demo/sprite ...