04_数据存储

Posted 渣爷

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了04_数据存储相关的知识,希望对你有一定的参考价值。

1. 理论概述

android数据存储方式:

  • SharedPreferences存储

  • 手机内部文件存储

  • 手机外部文件存储

  • sqlite数据库存储

  • 远程服务器存储

2. 数据存储开发

2.1 SharedPreferences存储

说明

  • SP存储专门用来存储一些单一的小数据

  • 存储数据的类型:boolean,float,int,long,String

  • 数据保存的路径:/data/data/packageName/shared_prefs/yyy.xml

  • 可以设置数据只能是当前应用读取,而别的应用不可以

  • 应用卸载时会删除数据

相关API

  • SharedPrefences:对应sp文件的接口

    • context.getSharedPreferences(String name,int mode):得到SP对象

      • name:文件名(不带.xml)

      • mode:生成的文件模式(是否是私有的,即其它应用是否可以访问)

    • Editor sp.edit():得到Editor对象

    • Xxx sp.getXxx(name, defaultValue):根据name得到对应的数据

  • Editor:能更新SP文件的接口

    • Editor put(name, value):保存一个键值对,没有真正保存到文件中

    • Editor remove(name)

    • commit():提交,数据真正保存到文件中 

示例

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <EditText
        android:id="@+id/et_sp_key"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="存储的key" />

    <EditText
        android:id="@+id/et_sp_value"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="存储的value" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="save"
            android:text="保 存" />
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="read"
            android:text="读 取" />
    </LinearLayout>

</LinearLayout>
activity_sp.xml
/**
 * 测试sp存储的界面
 */
public class SpActivity extends Activity {

    private EditText et_sp_key;
    private EditText et_sp_value;

    private SharedPreferences sp;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sp);

        et_sp_key = (EditText) findViewById(R.id.et_sp_key);
        et_sp_value = (EditText) findViewById(R.id.et_sp_value);

        //1. 得到sp对象
        sp = getSharedPreferences("atguigu", Context.MODE_PRIVATE);
    }

    public void save(View v) {
        //2. 得到editor对象
        SharedPreferences.Editor edit = sp.edit();
        //3. 得到输入的key/value
        String key = et_sp_key.getText().toString();
        String value = et_sp_value.getText().toString();
        //4. 使用editor保存key-value
        edit.putString(key, value).commit();
        //5. 提示
        Toast.makeText(this, "保存完成!", 0).show();
    }

    public void read(View v) {
        //1. 得到输入的key
        String key = et_sp_key.getText().toString();
        //2. 根据key读取对应的value
        String value = sp.getString(key, null);
        //3. 显示
        if(value==null) {
            Toast.makeText(this, "没有找到对应的value", 0).show();
        } else {
            et_sp_value.setText(value);
        }
    }
}
SpActivity.java
package com.atguigu.l04_datastorage;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    // 测试sp存储
    public void onClickSP(View v) {
        startActivity(new Intent(this, SpActivity.class));
    }

    // 测试手机内部文件存储
    public void onClickIF(View v) {
        startActivity(new Intent(this, IFActivity.class));
    }

    // 测试手机外部文件存储
    public void onClickOF(View v) {
        startActivity(new Intent(this, OFActivity.class));
    }

    public void onClickDB(View v) {

    }

    public void onClickNW(View v) {

    }
}
MainActivity.java

2.2 手机内部file存储

说明

  • 应用运行需要的一些较大的数据或图片可以用文件保存在手机内部

  • 文件类型:任意

  • 数据保存的路径:/data/data/projectPackage/files/

  • 可以设置数据只能是当前应用读取,而别的应用不可以

  • 应用卸载时会删除此数据

相关API

  • 读取文件

    • FileInputStream fis = openFileInput("logo.png");

  • 保存文件
    • FileOutputStream fos = openFileOutput("logo.png",MODE_PRIVATE);
  • 得到files文件夹对象
    • File filesDir = getFilesDir();  
  • 操作asserts下的文件
    • 得到Assetmanager:context.getAssets();    
    • 读取文件:InputStream open(filename);      
  • 加载图片文件
    • Bitmap BitmapFactory.decodeFile(String pathName)//.bmp/.png/.jpg
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:text="1. 将asserts下的logo.png保存到手机内部\\n2. 读取手机内部图片文件显示"
        android:textColor="#ff0000"
        android:textSize="15sp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <Button
            android:id="@+id/btn_if_save"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="save"
            android:text="保 存" />

        <Button
            android:id="@+id/btn_if_read"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="read"
            android:text="读 取" />
    </LinearLayout>

    <ImageView
        android:id="@+id/iv_if"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_launcher" />

</LinearLayout>
activity_if.xml
package com.atguigu.l04_datastorage;

import android.app.Activity;
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 测试手机内部文件存储
 */
public class IFActivity extends Activity {

    private ImageView iv_if;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_if);

        iv_if = findViewById(R.id.iv_if);
    }

    public void save(View view) throws IOException {
        //1.得到InputStream ->读取assets下的logo.png
        //得到AssetManager
        AssetManager manager = getAssets();
        //读取文件
        InputStream is = manager.open("logo.png");
        //2.得到OutputStream->/data/data/packageName/files/logo.png
        FileOutputStream fos = openFileOutput("logo.png", Context.MODE_PRIVATE);
        //3.边读边写
        byte[] buffer = new byte[1024];
        int len = 1;
        while((len = is.read(buffer)) != -1){
            fos.write(buffer,0,len);
        }
        fos.close();
        is.close();
        //4.提示
        Toast.makeText(this,"保存完成",Toast.LENGTH_SHORT).show();
    }

    //  /data/data/packageName/files/logo.png
    public void read(View view){
        //1. 得到图片文件的路径  /data/data/packageName/files
        String filesPath = getFilesDir().getAbsolutePath();
        String imagePath = filesPath + "/logo.png";
        //2.读取加载图片文件得到bitmap对象
        Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
        //3.将其设置到imageView中显示
        iv_if.setImageBitmap(bitmap);
    }
}
IFActivity.java

2.3 手机外部file存储

说明

  • 应用运行用到的数据文件(如图片)可以保存到sd卡中

  • 文件类型:任意

  • 数据保存的路径:

    • 路径1:/storage/sdcard/Android/data/packageName/files/

    • 路径2:/storage/sdcard/xx/

  • 路径1:其它应用可以访问,应用卸载时删除

  • 路径2:共它应用可以访问,应用卸载时不会删除

  • 必须保证sd卡挂载在手机上才能读写,否则不能操作

相关API

  • Environment:操作SD卡的工具类

    • 得到SD卡的状态:Environment.getExternalStorageState()

    • 提到SD卡的路径:Environment.getExternalStorageDirectory()

    • SD卡可读写的挂载状态值:Enviroment.MEDIA_MOUNTED

  • context.getExternalFilesDir():

    • 得到/mnt/sdcard/Android/data/package_name/files/xxx.txt

  • 操作SD卡的权限:

    • android.permission.WRITE_EXTERNAL_STORAGE

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <EditText
        android:id="@+id/et_of_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="存储的文件名" />

    <EditText
        android:id="@+id/et_of_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="存储的文件内容" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="save"
            android:text="保 存" />
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="read"
            android:text="读 取" />
    </LinearLayout>
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="save2"
            android:text="保 存2" />
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="read2"
            android:text="读 取2" />
    </LinearLayout>

</LinearLayout>
activity_of.xml
package com.atguigu.l04_datastorage;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

/**
 * 测试手机外部文件存储
 */
public class OFActivity extends Activity {

    private EditText et_of_name;
    private EditText et_of_content;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_of);
        
        et_of_name = (EditText) findViewById(R.id.et_of_name);
        et_of_content = (EditText) findViewById(R.id.et_of_content);
    }

    public void save(View v) throws IOException {
        //1. 判断sd卡状态, 如果是挂载的状态才继续, 否则提示
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            //2. 读取输入的文件名/内容
            String fileName = et_of_name.getText().toString();
            String content = et_of_content.getText().toString();
            //3. 得到指定文件的OutputStream
                //1).得到sd卡下的files路径
            String filesPath = getExternalFilesDir(null).getAbsolutePath();
                //2).组成完整路径
            String filePath = filesPath+"/"+fileName;
                //3). 创建FileOutputStream
            FileOutputStream fos = new FileOutputStream(filePath);
            //4. 写数据 
            fos.write(content.getBytes("utf-8"));
            fos.close();
            //5. 提示
            Toast.makeText(this, "保存完成", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "sd卡没有挂载", Toast.LENGTH_SHORT).show();
        }
        
    }

    public void read(View v) throws Exception {
        
        // 1. 判断sd卡状态, 如果是挂载的状态才继续, 否则提示
        if (Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) {
            // 2. 读取输入的文件名
            String fileName = et_of_name.getText().toString();
            // 3. 得到指定文件的InputStream
                // 1).得到sd卡下的files路径
            String filesPath = getExternalFilesDir(null).getAbsolutePath();
                // 2).组成完整路径
            String filePath = filesPath + "/" + fileName;
                // 3). 创建FileInputStream
            FileInputStream fis = new FileInputStream(filePath);
            // 4. 读取数据, 成String
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = -1;
            while((len=fis.read(buffer))!=-1) {
                baos.write(buffer, 0, len);
            }
            String content = baos.toString();
            
            // 5. 显示
            et_of_content.setText(content);
        } else {
            Toast.makeText(this, "sd卡没有挂载", Toast.LENGTH_SHORT).show();
        }
    }

    //  /storage/sdcard/atguigu/xxx.txt
    public void save2(View v) throws IOException {
        //1. 判断sd卡状态, 如果是挂载的状态才继续, 否则提示
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            //2. 读取输入的文件名/内容
            String fileName = et_of_name.getText().toString();
            String content = et_of_content.getText().toString();
            //3. 得到指定文件的OutputStream
                //1). /storage/sdcard/
            String sdPath = Environment.getExternalStorageDirectory().getAbsolutePath();
                //2). /storage/sdcard/atguigu/(创建文件夹)
            File file = new File(sdPath+"/atguigu");
            if(!file.exists()) {
                file.mkdirs();//创建文件夹
            }
                //3). /storage/sdcard/atguigu/xxx.txt
            String filePath = sdPath+"/atguigu/"+fileName;
                //4). 创建输出流
            FileOutputStream fos = new FileOutputStream(filePath);
            //4. 写数据 
            fos.write(content.getBytes("utf-8"));
            fos.close();
            //5. 提示
            Toast.makeText(this, "保存完成", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "sd卡没有挂载", Toast.LENGTH_SHORT).show();
        }
    }

    public void read2(View v) throws Exception {
        // 1. 判断sd卡状态, 如果是挂载的状态才继续, 否则提示
        if (Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) {
            // 2. 读取输入的文件名
            String fileName = et_of_name.getText().toString();
            // 3. 得到指定文件的InputStream
            String sdPath = Environment.getExternalStorageDirectory().getAbsolutePath();
            String filePath = sdPath+"/atguigu/"+fileName;
            FileInputStream fis = new FileInputStream(filePath);
            // 4. 读取数据, 成String
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = -1;
            while((len=fis.read(buffer))!=-1) {
                baos.write(buffer, 0, len);
            }
            String content = baos.toString();
            fis.close();
            // 5. 显示
            et_of_content.setText(content);
        } else {
            Toast.makeText(this, "sd卡没有挂载", Toast.LENGTH_SHORT).show();
        }
    }
}
OFActivity.java

比较内部文件与外部文件存储?

  1. 存储空间的大小

  2. 是否是私有的

  3. 应用卸载是否自动删除

2.4 SQLite数据库存储

说明

  • 应用运行需要保存一系列有一定结构的数据,比如说公司员工信息

  • 文件类型:db

  • 数据保存的路径 :/data/data/projectPackage/databases/xxx.db

  • 默认情况下其它应用不能访问,当前应用可以通过ContentProvider提供其它应用操作

  • 应用卸载时会删除此数据

SQLite数据库

SQLite(http://www.sqlite.org),是一款轻型的关系型数据库服务器,移动设备的数据库存储都使用SQLite,它的特点:

  • 安装文件小:最小只有几百K,Android系统已经安装

  • 支持多操作系统:Android,WP,ios,Windows,Linux等

  • 支持多语言:比如Java、php、C#等

  • 处理速度快:处理速度比mysql,Oracle,SQLServer都要快(数据量不是特别大)

  • SQLite中的一个数据库就是一个.db文件(本质上.db的后缀都可以不指定)

SQLite数据库命令行

  • adb shell 进入系统根目录

  • cd data/data/…/databases:进入包含数据库文件的文件夹下

  • sqlite3 contacts2.db:使用sqlite3命令连接指定的数据库文件,进入连接模式

  • help:查看命令列表

  • tables:查看所有表的列表

  • 执行 insert/delete/update/select语句

  • exit:退出数据库连接模式

  • Ctrl+C:直接退出shell模式

数据类型

SQLite支持的数据类型与MySQL相似,常用的数据类型

  • INT/INTEGER:整数

  • FLOAT/DOUBLE:小数

  • CHAR/VARCHAR/TEXT:字符串文本

  • BLOB:文件

  • DATE/DATETIME:日期/日期时间

SQLite建表

SQLite操作数据库的sql语句基本与mysql一样,但需要注意下面2点:

  • 最大的不同在于创建表时可以不用指定字段类型,sqlite可以适时的自动转换,但除varchar类型外最好指定类型

  • sqlite中的主键名称建议使用_id