Android系统的五种数据存储形式(一)

  • A+
所属分类:移动安全

转自:huang502博客园

Android系统有五种数据存储形式,分别是文件存储、SP存储、数据库存储、contentprovider 内容提供者、网络存储。其中,前四个是本地存储。存储的类型包括简单文本、窗口状态存储、音频视频数据、XML注册文件的各种数据。各种存储形式的特点不尽相同,因此对于不同的数据类型有着固定的存储形式,本文为演示方便给出的案例基本相同,都是是采用账号登录来演示数据存储,保存账号和密码信息,下次登录时记住账号和密码。重在说明各种存储形式的原理。

    文件存储:

    以I/O流的形式把数据存入手机内存或SD卡,可以存储大数据,如音乐、图片或视频等。对于手机内存来说系统会根据每个应用的包名创建一个/data/data/包名/的文件夹,访问自己包名下的目录是不需要权限的,并且 Android 已经提供了非常简便的 API 可以直接去访问该文件夹。访问时可以用getFilesDir()和getCacheDir(),两个的区别是系统会自动清理后者中的内容。

    SD卡中的文件通常位于mnt/sdcard目录下,不同生产商生产的手机这个路径可能不同。操作sd卡的时通常要判断下sd卡是否可用以及剩余空间是否足够,因为部分手机的SD卡可卸载,SD卡处于非挂载状态时,无法进行读写操作。另外一点,对SD卡的读取和写入操作均需要相应的权限,否则无法完成。获取SD卡路径的方法是Environment.getExternalStorageDirectory(),其余操作与文件存储基本类似。


   文件存储位置:

Android系统的五种数据存储形式(一)

  SD卡存储路径:

Android系统的五种数据存储形式(一)


数据存储在手机内存的实现方法:

package com.example.qqload;import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.InputStreamReader;import com.example.qqload_sp.R;import android.os.Bundle;import android.app.Activity;import android.content.SharedPreferences;import android.content.SharedPreferences.Editor;import android.text.TextUtils;import android.view.Menu;import android.view.TextureView;import android.view.View;import android.widget.Button;import android.widget.CheckBox;import android.widget.EditText;import android.widget.Toast;public class MainActivity extends Activity {    private EditText et_qq;    private EditText et_password;    private CheckBox cb_remenber;      @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);         et_qq = (EditText) findViewById(R.id.et_qq);         et_password = (EditText) findViewById(R.id.et_password);         cb_remenber = (CheckBox) findViewById(R.id.cb_remenber);         File file = new File(getFilesDir(), "info.txt");//        File file = new File(getCacheDir(), "info.txt");   缓存中存放数据         if (file.exists() && file.length() > 0) {            try {                 FileInputStream fis = new FileInputStream(file);                 BufferedReader br = new BufferedReader(new InputStreamReader(                         fis));                 String line = br.readLine();                 String qq = line.split("##")[0];                 String password = line.split("##")[1];                 et_qq.setText(qq);                 et_password.setText(password);                 fis.close();             } catch (Exception e) {                // TODO Auto-generated catch block                e.printStackTrace();             }         }     }    public void login(View view) {         String qq = et_qq.getText().toString().trim();         String password = et_password.getText().toString().trim();        if (TextUtils.isEmpty(qq) || TextUtils.isEmpty(password)) {             Toast.makeText(this, "密码或者用户名不能为空", 0).show();            return;         }        if (cb_remenber.isChecked()) {             File file = new File(getFilesDir(), "info.txt");            try {                 FileOutputStream fos = new FileOutputStream(file);                 fos.write((qq + "##" + password).getBytes());                 fos.close();                 Toast.makeText(MainActivity.this, "保存成功", 0).show();             } catch (Exception e) {                 Toast.makeText(MainActivity.this, "保存失败", 0).show();                 e.printStackTrace();             }         }     } }

 

数据存储在SD卡中的实现方法:     

package com.example.qqload;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.text.Format;

import com.example.qqload_sp.R;

import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.view.Menu;
import android.view.TextureView;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity {
   
private EditText et_qq;
   
private EditText et_password;
   
private CheckBox cb_remenber;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
       
super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_qq 
= (EditText) findViewById(R.id.et_qq);
        et_password 
= (EditText) findViewById(R.id.et_password);
        cb_remenber 
= (CheckBox) findViewById(R.id.cb_remenber);
        File file 
new File(Environment.getExternalStorageDirectory(), "info.txt");
       
if (file.exists() && file.length() > 0) {
           
try {
                FileInputStream fis 
new FileInputStream(file);
                BufferedReader br 
new BufferedReader(new InputStreamReader(
                        fis));
                String line 
= br.readLine();
                String qq 
= line.split("##")[0];
                String password 
= line.split("##")[1];
                et_qq.setText(qq);
                et_password.setText(password);
                fis.close();
            } 
catch (Exception e) {
               
// TODO Auto-generated catch block                e.printStackTrace();
            }
        }
    }

    public void login(View view) {
        String qq 
= et_qq.getText().toString().trim();
        String password 
= et_password.getText().toString().trim();
       
if (TextUtils.isEmpty(qq) || TextUtils.isEmpty(password)) {
            Toast.makeText(
this, "密码或者用户名不能为空", 0).show();
           
return;
        }
       
if (cb_remenber.isChecked()) {
            File file 
new File(Environment.getExternalStorageDirectory(), "info.txt");
           
//判断SD卡是否挂载
            if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
                Toast.makeText(MainActivity.
this, "SD卡不可用", 0).show();
               
return;
            }
           
//判断SD卡大小是否充足
            long size = Environment.getExternalStorageDirectory().getFreeSpace();
            String info 
= Formatter.formatFileSize(this, size);
           
//此处存储数据较小就不进行判断
            Toast.makeText(this, "可用空间" + info, 0).show();
           
           
try {
                FileOutputStream fos 
new FileOutputStream(file);
                fos.write((qq 
+ "##" + password).getBytes());
                fos.close();
                Toast.makeText(MainActivity.
this, "保存成功", 0).show();
            } 
catch (Exception e) {
                Toast.makeText(MainActivity.
this, "保存失败", 0).show();
                e.printStackTrace();
            }
        }
    }

}


SP存储:

     SP存储本质上是一个XML文件,以键值对的形式存入手机内存中。常用于存储简单的参数设置,如登陆账号密码的存储,窗口功能状态的存储等,该存储文件位于:data/data/包名/shared_prefs文件夹中。使用的时候,首先需要通过context.getSharedPrefrences(String name,int mode)获取SharedPrefrences的实例对象,存储数据时,用SharedPrefrences的实例对象得到SharedPrefrences文件的编辑器,在编辑器中用putXxx()添加数据,之后务必用commit提交数据,否则无法获取数据。取数据时,直接用getXxx()方法。


     sp存储自动生成xml文件,其的路径如下:

Android系统的五种数据存储形式(一)

sp存储的实现方法:

package com.example.qqload;
import com.example.qqload_sp.R;

import android.os.Bundle;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.text.TextUtils;
import android.view.Menu;
import android.view.TextureView;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
   
private EditText et_qq;
   
private EditText et_password;
   
private CheckBox cb_remenber;
     
private SharedPreferences sp;
    @Override
   
protected void onCreate(Bundle savedInstanceState) {
       
super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_qq 
= (EditText) findViewById(R.id.et_qq);
        et_password 
= (EditText) findViewById(R.id.et_password);
        cb_remenber 
= (CheckBox) findViewById(R.id.cb_remenber);
        sp 
this.getSharedPreferences("config", 0);
        String qq 
= sp.getString("qq","");
        String password 
= sp.getString("password","");
        et_qq.setText(qq);
        et_password.setText(password);
    }
   
public void login(View view){
        String qq 
= et_qq.getText().toString().trim();
        String password 
= et_password.getText().toString().trim();
       
if(TextUtils.isEmpty(qq)||TextUtils.isEmpty(password)){
            Toast.makeText(
this,"密码或者用户名不能为空",0).show();
           
return;
        }
       
if(cb_remenber.isChecked()){
            Editor edit 
= sp.edit();
            edit.putString(
"qq",qq);
            edit.putString(
"password",password);
            edit.commit();
        }
    }

}


数据库存储:

      数据库所有信息都存储在单一文件内,占用内存小,并且支持基本SQL语法,是项目中经常被采用的一种数据存储方式,通常用于存储用户信息等,例如在手机上做一个学生信息管理系统。SQLite 是一款内置到移动设备上的轻量型的数据库,SQLiteOpenHelper 是Android 提供的一个抽象工具类,负责管理数据库的创建、升级工作。数据库的路径为:/data/data/应用包名/databases/数据库。如果想创建数据库,就需要自定义一个类继承SQLiteOpenHelper,然后覆写其中的抽象方法,指定数据库名、版本号。在onCreate() 方法中通过执行sql 语句实现表的创建。如果只是创建出来该类并不会真正的去创建数据库,而是需要通过执行helper.getWritableDatabase()或者hepler.getReadableDatabase()。另外想要对创建的数据库进行增删改查的操作可以单独定义一个类实现。增删改查操作有两种方式,一是直接执行sql语句,另一个是Android自身的API实现。用数据库实现账号登录显得有些大材小用,为演示数据库的原理本文给出的案例是用数据库记录多个用户的账号和密码信息,并把最后一个账号信息回显在界面。但实际应用中很少这样做。

     从手机文件中导出数据库文件并不可以直接打开,因此可以用可视化工具和sqlite3操作工具进行查看。这里介绍sqlite3工具的使用。具体需要的步骤如下: 

        1. 执行adb shell命令进入Linuxne内核;

        2. 使用cd进入数据库所在的路径 cd: /data/data/应用包名/databases;

        3. 进入数据库模式: sqlite3 数据库名.db;

        4. 执行SQL语句        


        Sqlite3操作演示:

Android系统的五种数据存储形式(一)

数据库存储路径:

Android系统的五种数据存储形式(一)

数据库实现方法,先创建一个类继承SqliteOpenHelper,在类中创建数据库和表:

package com.example.qqload.db;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;

public class UserDBOpenhelper extends SQLiteOpenHelper {
   
public UserDBOpenhelper(Context context) {
       
super(context, "user.db", null, 1);
       
// TODO Auto-generated constructor stub    }
    @Override
   
public void onCreate(SQLiteDatabase arg0) {
        arg0.execSQL(
"create table user (_id integer primary key autoincrement,name vachar(20),password varchar(20))");
    }
    @Override
   
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
       
// TODO Auto-generated method stub    }

}


创建一个工具类实现对数据库的操作:


package com.example.qqload.db.dao;

import java.util.ArrayList;
import java.util.List;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.example.qqload.db.UserDBOpenhelper;

public class UserDao {
   
private UserDBOpenhelper helper; 
   
public UserDao(Context context){
        helper 
new UserDBOpenhelper(context);
    }
   
public long add(String name,String password){
        SQLiteDatabase  db 
= helper.getWritableDatabase();
       
//用SQL语句实现增加数据的功能
       
//db.execSQL("insert into user (name,passeord) values (?,?)", new Object[]{name,password});
       
//android自身API实现修改功能可以有返回值
        ContentValues values =new ContentValues();
        values.put(
"name", name);
        values.put(
"password", password);
       
long result = db.insert("user", null, values); //带返回值,表示添加在哪一行        db.close();
       
return result;
    }
   
public List<user> findAll(){
        List
<user> list =new ArrayList<user>();
        SQLiteDatabase  db 
= helper.getReadableDatabase();
       
//Cursor cursor = db.rawQuery("select name, password from user", null);
        Cursor cursor =  db.query("user", new String[]{"name","password"}, nullnullnullnullnull);
       
while(cursor.moveToNext()){
            String name 
= cursor.getString(0);
            String password 
= cursor.getString(1);
            user us 
new user();
            us.setName(name);
            us.setPassword(password);
            list.add(us);
        }
        cursor.close();
        db.close();
       
return list;
    }

}


在主方法中实现账号登录和记录

package com.example.qqload;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.util.List;

import com.example.qqload.db.dao.UserDao;
import com.example.qqload.db.dao.user;
import com.example.qqload.R;

import android.os.Bundle;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.text.TextUtils;
import android.view.Menu;
import android.view.TextureView;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity {
   
private EditText et_qq;
   
private EditText et_password;
   
private CheckBox cb_remenber;
   
private UserDao dao;
   
private List<user> list;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
       
super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_qq 
= (EditText) findViewById(R.id.et_qq);
        et_password 
= (EditText) findViewById(R.id.et_password);
        cb_remenber 
= (CheckBox) findViewById(R.id.cb_remenber);
        user u 
new user();
        dao 
new UserDao(MainActivity.this);
        list 
= dao.findAll();
       
if (list.size() == 0) {
            et_qq.setText(
"");
            et_password.setText(
"");
        } 
else {
            System.out.println(
"大小:" + list.size());
           
for (int i = 0; i < list.size(); i++) {
                System.out.println(list.get(i).getName() 
+ "::::" + list.get(i).getPassword());
            }
            u 
= list.get(list.size()-1);
            String qq 
= u.getName();
            String password 
= u.getPassword();
            et_qq.setText(qq);
            et_password.setText(password);
        }
    }

    public void login(View view) {
        String qq 
= et_qq.getText().toString().trim();
        String password 
= et_password.getText().toString().trim();
       
if (TextUtils.isEmpty(qq) || TextUtils.isEmpty(password)) {
            Toast.makeText(
this, "密码或者用户名不能为空", 0).show();
           
return;
        }
       
if (cb_remenber.isChecked()) {
            dao.add(qq, password);           
//在工具类添加增加功能
            Toast.makeText(MainActivity.this, "保存成功", 0).show();
        }
    }

}


用数据库实现账号登录案例的目录结构如下所示:

Android系统的五种数据存储形式(一)


本文始发于微信公众号(LemonSec):Android系统的五种数据存储形式(一)

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: