—— 大家都知道,数据和算法是一个应用程序的核心。所以,学好数据存储是非常有必要的。
——Android数据的存储有多种方式,比如ContentProvider(内容提供者)、SQLite(嵌入式数据库)存储、SharedPreferences存储、文件(File)存储等。文件(File)存储是最简单的数据存储方式,也是用得较少的一种数据存储方式。
——在这里,不知道大家有没有发现文件(File)存储似曾相识啊!没错,所谓的文件(File)存储不过是简单的Java.IO流罢了。那么,Java.IO流来到Android平台上怎么使用呢?不妨先想想,这就有点像老大来到一个有出息的小弟家做客,如果你是这个有出息的小弟,你该怎么做?不管怎样是不是先让个人去给老大带路呀!礼貌必不可少的。回到主题,为了让Java.IO流在安卓平台上起到好的发挥作用,这里需要使用Context来给老大带路!Context中都提供了相应的函数来支持,使用Context不但操作简单方便,最重要的是Context会帮助我们管理这些文件,也可以方便帮助我们控制文件的访问权限。
——了解Context的得力之处:(1)FileOutputStream out = context.openFileOutput(String filename,int mode); 以mode模式获得文件输出流,(2)out.write(byte[]b)。openFileOutput方法中有两个参数,filename是文件名(不包含路径),mode是代表模式,其中,mode模式有四种,MODE_PRIVATE:私有覆盖模式 (默认模式),MODE_APPEND:私有追加模式,注意:这两种模式只能被当前应用访问;还有两种模式在Android4.2以后被废除。默认情况下会将文件存储到/data/data//files的文件。
——很多文件存储的例子写的都不一样,你会发现一个大神写的是一样,另一个大神写的是一样,这里有必要归纳一下,一种是简单的版本(直接是上面说到的两个步骤),还有一种是复杂的版本(就是需要用到转换流和缓冲区等),根据需要来选择就好,最起码别人写的要看懂哈!知道是怎么一回事就行。下面贴出代码:
简单版:
/**
* Created by Dell on 2017/3/22.
*/
public class MyContextFile extends Activity {
private EditText writeFileContent;
private TextView displayContent;
private Button writeFileButton,readFileButton;
private String writeinfo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_file);
initLayout();
}
private void initLayout(){
writeFileContent=(EditText) findViewById(R.id.write_Edit);
displayContent=(TextView) findViewById(R.id.display_textView);
writeFileButton=(Button) findViewById(R.id.write_Button);
readFileButton=(Button) findViewById(R.id.read_Button);
writeFileButton.setOnClickListener(writeFileClickListener);
readFileButton.setOnClickListener(readFileClickListener);
}
//将输入的信息写入到文件中
View.OnClickListener writeFileClickListener=new View.OnClickListener() {
@Override
public void onClick(View v) {
//通过EditText获得输入的信息
writeinfo=writeFileContent.getText().toString();
FileOutputStream fileOutputStream=null;
try {
//通过openFileOutput()方法得的一个文件输出流
fileOutputStream=openFileOutput("user.txt",MODE_PRIVATE);
//将输入的信息写入到文件
fileOutputStream.write(writeinfo.getBytes());
Toast.makeText(MyContextFile.this, "写入文件成功",
Toast.LENGTH_SHORT).show();
}catch (FileNotFoundException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}finally {
if (fileOutputStream!=null){
try {
fileOutputStream.close();//关闭文件流
}catch (IOException e){
e.printStackTrace();
}
fileOutputStream=null;
}
}
}
};
//读取文件中的信息
View.OnClickListener readFileClickListener=new View.OnClickListener() {
@Override
public void onClick(View v) {
FileInputStream fileInputStream=null;
try {
//通过openFileOutput()方法得的一个文件写入流
fileInputStream=openFileInput("user.txt");
//定义一个字节数组来缓存读取的字节
byte[] cache=new byte[fileInputStream.available()];
//读取文件
fileInputStream.read(cache);
displayContent.setText(":"+new String(cache));
}catch (FileNotFoundException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}finally {
if (fileInputStream!=null){
try {
fileInputStream.close();//关闭文件流
}catch (IOException e){
e.printStackTrace();
}
fileInputStream=null;
}
}
}
};
}
复杂版:
package com.xhm.demo.myandroidsql;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
/**
* Created by Dell on 2017/3/22.
*/
public class FileContext extends Activity {
String data="data";
FileOutputStream out=null;
BufferedWriter bw=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
//调用Context.openFileOutput()方法获得java文件
// 输出流(FileOutputStream)并返回对象
out=openFileOutput("data", Context.MODE_PRIVATE);
//借助FileOutputStream构建出一个OutputStreamWriter对象
OutputStreamWriter osw=new OutputStreamWriter(out);
//借助OutputStreamWriter构建出一个BufferedWriter对象
bw=new BufferedWriter(osw);
bw.write(data);//写内容
}catch (IOException e){
e.printStackTrace();
}finally {
try {
if (bw!=null){
bw.close();//关闭文件流
}
}catch (IOException e){
e.printStackTrace();
}
}
}
}
——是不是觉得安卓文件存储很简单呀!是它和Java.IO流有关系而简单,也是因为它和Java.IO流有关系而复杂。上面的例子都是在安卓存储理想状态下执行的,请问你了解安卓的数据存储情况吗?有那些分类,各有什么不同、采取什么方式等等?
——学习就像考虑事情一样要周。接下来了解一下安卓的存储情况吧!Android存储空间分为内部存储空间(Internal Storage)和外部存储空间(External Storage)。简单的说就是手机内存和SD卡这两种存储空间。内部存储空间十分有限,因而显得可贵,所以我们要尽可能避免使用;另外,它也是系统本身和系统应用程序主要的数据存储所在地,一旦内部存储空间耗尽,手机 也就无法使用了。 使用内部存储主要有二个方式,一个是文件操作,一个是文件夹操作。注意:尤其是在开发应用程序是要为手机用户解应用数据到底存在哪里好?想想如果把手机用户的内存存了很多数据,内存用完用户会反感的,那如果我们把数据存到SD卡安全数不高也会引来用户的反感。那怎么办呢?这是值得考虑的,实在不行我们采取中庸之道,在存储数据之前我们先来判断用户手机内存和SD卡还剩多少内存,把数据存到内存最多的那个地方去,不痛不痒,妙。
1.需要判断sd卡是否可用:
/**
* Check if the primary "external" storage device is available.
*
* @return
*/
public static boolean hasSDCardMounted() {
String state = Environment.getExternalStorageState();
if (state != null && state.equals(Environment.MEDIA_MOUNTED)) {
return true;
} else {
return false;
}
}
2.应用数据存放路径,同其他应用应该保持一致,应用卸载时,清除数据:
3.需要判断两者的可用空间:在API level 9及其以上时,File对象的getFreeSpace()方法获取系统root用户可用空间;
getUsableSpace()取非root用户可用空间。当有多个存储可用时获取磁盘用量,根据当前系统情况选用合适的存储。
根据系统存储用量,合理设定app所用的空间大小;运行时,也可做动态调整。
@TargetApi(VERSION_CODES.GINGERBREAD)
public static long getUsableSpace(File path) {
if (path == null) {
return -1;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
return path.getUsableSpace();
} else {
if (!path.exists()) {
return 0;
} else {
final StatFs stats = new StatFs(path.getPath());
return (long) stats.getBlockSize() * (long) stats.getAvailableBlocks();
}
}
}
——内部存储的唯一缺点就是空间有限、珍贵;最大的有点就是安全数高(只允许本应用程序访问,且一旦删除应用程序,数据一会跟着被删除)。外部存储空间是指手机出厂的时候不存在,用户在使用时候可以自由添加的外部存储介质比如TS卡,SD卡等闪存储介质。其实安卓系统它是要依赖于外部存储卡的,因为对于Android系统,如果没有外部存储卡,很多 的系统应用无法使用,比如多媒体相关的应用程序无法使用。优点就是存储空间大,不用担心去清除数据。外部存储的缺点就是不是很稳定,对于Android手机来讲可以说,很不稳定,本身闪存介质就容易出问 题,SD卡处于不能正常使用的状态十分多。