Android 文件存储

1.IO文件读取

IO流类图
IO流
分类

按照读取数据类型不同分为字节流字符流
按照数据流向不同分为输入流和```输出流

常用方式
字节流FileInputStream 和 FileOutputStream文件读写
//写入文件
 private void writeFile() {
        FileOutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(path);
            String str = "asdasdadadad";
            outputStream.write(str.getBytes());
            outputStream.close();
        } 
       ...注意异常处理
    }
//读取文件
FileInputStream inputStream = null;
try {
      inputStream = new FileInputStream(file);
      StringBuilder builder = new StringBuilder();
      int i = 0;
      while ((i = inputStream.read() )!= -1){
           builder.append((char)i);
       }
      //文件信息
      builder.toString();
     inputStream.close();
}..异常处理
BufferedOutputStream与BufferedInputStream

BufferedInputStream是带缓冲区的输入流,默认缓冲区大小是8M,能够减少访问磁盘的次数,提高文件读取性能;BufferedOutputStream是带缓冲区的输出流,能够提高文件的写入效率。BufferedInputStream与BufferedOutputStream分别是FilterInputStream类和FilterOutputStream类的子类,实现了装饰设计模式。

FileOutputStream outputStream = null;
BufferedOutputStream bufferedOutputStream;
 try {
       outputStream = new FileOutputStream(path);
       bufferedOutputStream = new BufferedOutputStream(outputStream);
       String str = "sssssssasdafafasda";
       bufferedOutputStream.write(str.getBytes());
       //写完毕后要将数据刷新到文件中
       bufferedOutputStream.flush();
       outputStream.close();
       bufferedOutputStream.close();
 } //异常处理
FileInputStream inputStream = null;
BufferedInputStream bufferedInputStream;
try {
      inputStream = new FileInputStream(file);
      bufferedInputStream = new BufferedInputStream(inputStream);
      StringBuilder builder = new StringBuilder();
      //缓冲区 不设置默认为8K
      byte[] bytes = new byte[1024];
      int i = 0;
      while ((i = bufferedInputStream.read(bytes) )!= -1){
           builder.append(new String(bytes));
       }
      builder.toString()
      inputStream.close();
}//异常处理
字符流操作文件

FileWriterFileReader读写文件

    //写文件
    private void writerFile() {
        FileWriter writer = null;
        try {
            writer = new FileWriter(path);
            String str = "中文测试呢";
            writer.write(str);
            writer.close();
        } //异常处理
    }
//读文件
private void readerFile() {
        FileReader reader = null;
        try {
            reader = new FileReader(file);
            StringBuilder builder = new StringBuilder();
            int i = 0;
            while ((i = reader.read() )!= -1){
                builder.append((char)i);
            }
            mResult.setText(builder.toString());
            reader.close();
        } //异常处理
    }
BufferedReader和BufferedWriter,带缓冲区的字符流。
  private void bufferReaderFile() {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader(file));
            StringBuilder builder = new StringBuilder();
            String str = "";
            while ((str = reader.readLine()) != null){
                builder.append(str);
            }
            mResult.setText(builder.toString());
            reader.close();
        } //异常处理
    }
    private void  bufferWriterFile() {
        BufferedWriter writer = null;
        try {
            writer = new BufferedWriter(new FileWriter(path));
            String str = "BufferedWriter测试呢";
            writer.write(str);
            writer.close();
        } //异常处理
    }
InputStreamReader将字节流转换为字符流
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "GB2312");
ObjectOutputStream与ObjectInputStream序列化与反序列化
    //序列化
    private void writeObject(){
        ObjectOutputStream objectOutputStream = null;
        try {
            objectOutputStream = new ObjectOutputStream(new FileOutputStream(path));
            Student student = new Student();
            objectOutputStream.writeObject(student);
            objectOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (null != objectOutputStream){
                try {
                    objectOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    //反序列化
    private void readObject(){
        ObjectInputStream objectInputStream = null;
        try {
            objectInputStream = new ObjectInputStream(new FileInputStream(path));
            Student student = (Student) objectInputStream.readObject();
            mResult.setText(student.toString());
            objectInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (null != objectInputStream){
                try {
                    objectInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
1.序列化 ID 问题

虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(就是 private static final long serialVersionUID = 1L)。

2.静态变量序列化

序列化保存的是对象的状态,静态变量属于类的状态,因此 序列化并不保存静态变量。

3.父类的序列化与 Transient 关键字

一个子类实现了 Serializable 接口,它的父类都没有实现 Serializable 接口,序列化该子类对象,然后反序列化后输出父类定义的某变量的数值,该变量数值与序列化时的数值不同。
解决方法:要想将父类对象也序列化,就需要让父类也实现Serializable 接口。或者有默认的无参的构造函数,在构造函数中完成初始化。
Transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。

4.自定义序列化过程

虚拟机会试图调用对象类里的 writeObject 和 readObject 方法,进行用户自定义的序列化和反序列化,如果没有这样的方法,则默认调用是 ObjectOutputStream 的 defaultWriteObject 方法以及 ObjectInputStream 的 defaultReadObject 方法。用户自定义的 writeObject 和 readObject 方法可以允许用户控制序列化的过程。

   //序列化过程
    private void writeObject(ObjectOutputStream out) {
        try {
            ObjectOutputStream.PutField putFields = out.putFields();
            career = "new Student";//模拟加密
            putFields.put("career", career);
            out.writeFields();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
   //反序列化过程
    private void readObject(ObjectInputStream in){
        try {
            ObjectInputStream.GetField getField = in.readFields();
            career = (String) getField.get("career", "");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
5.序列化存储规则

Java 序列化机制为了节省磁盘空间,具有特定的存储规则,当写入文件的为同一对象时,并不会再将对象的内容进行存储,而只是再次存储一份引用,新增一些控制信息。反序列化时,恢复引用关系该存储规则极大的节省了存储空间。

2.sqlite数据库

sqlite数据库的使用:
1、继承SQLiteOpenHelper

public class DbHelper extends SQLiteOpenHelper {

    //数据库名称
    private final static String dbName = "test.db";
    //表名称
    public final static String dbTable = "testTable";

    public DbHelper(Context context){
        this(context,dbName,null,1);
    }

    public DbHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        //上下文,数据库名称,游标工厂,版本号
        super(context, name, factory, version);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        //创建表操作
        String sql = "create table if not exists "+ dbTable+"(Id integer /*primary key*/ , Name text ,
 Price integer , Age integer)";
        sqLiteDatabase.execSQL(sql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
        //更新操作一般有如下步骤,本次演示只默认删除重建
        if (oldVersion != newVersion) {
            //1.创建临时表保存数据
            //2.删除现有表
            //3.创建新表
            //4.复制临时表数据至新表
            //5.删除临时表
            sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + dbTable);
            onCreate(sqLiteDatabase);
        }
    }
}

2、创建数据库操作类,持有SQLiteOpenHelper子类对象,操作数据增删改查:

   //插入
   public void insert(){
        SQLiteDatabase writableDatabase = mDbHelper.getWritableDatabase();
        writableDatabase.beginTransaction();
        writableDatabase.execSQL("insert into " + mDbHelper.dbTable+"(Id,Name,Price,Age)values (1,'xj2',12,18)");
        writableDatabase.execSQL("insert into " + mDbHelper.dbTable+"(Id,Name,Price,Age)values (2,'xj3',13,18)");
        writableDatabase.execSQL("insert into " + mDbHelper.dbTable+"(Id,Name,Price,Age)values (3,'xj4',14,18)");
        writableDatabase.execSQL("insert into " + mDbHelper.dbTable+"(Id,Name,Price,Age)values (4,'xj5',15,18)");
        writableDatabase.execSQL("insert into " + mDbHelper.dbTable+"(Id,Name,Price,Age)values (5,'xj6',16,18)");
        writableDatabase.execSQL("insert into " + mDbHelper.dbTable+"(Id,Name,Price,Age)values (6,'xj7',17,18)");
        writableDatabase.setTransactionSuccessful();
        writableDatabase.endTransaction();
    }
//查询
public String  query(){
        SQLiteDatabase writableDatabase = mDbHelper.getWritableDatabase();
        Cursor query = writableDatabase.query(mDbHelper.dbTable, null, null, null, null, null, null);
        StringBuilder builder = new StringBuilder();
        while (query.moveToNext()){
           //查询数据
           int id = query.getInt(query.getColumnIndex("Id"));
        }
        return builder.toString();
    }
其余方法等同.数据库详细语法后续再详细学习。

数据库操作有两种方式,一种如insert方法一样执行SQL语句,另一种如query方法一样使用SQLiteDatabase 封装过的方法。
sqlite是线程安全的吗
Android中SQLiteDatabase为sqlite提供了线程安全的保证,因此Android中sqlite数据库是线程安全的。
sqlite是线程安全的吗
数据库保存在/data/data/pageName/databases/dbName.db,其中pageName为包名,dbName为数据库名称。

3.SharedPreferences

SharedPreferences是Android轻量级的存储方式,使用方式如下

    public void saveSp(){
        SharedPreferences preferences = getSharedPreferences("perfer_file",MODE_PRIVATE);
        SharedPreferences.Editor edit = preferences.edit();
        edit.putString("key",value);
        edit.putInt("key",value);
        ....
        edit.apply();/edit.commit();
    }

    public void readSp(){
        SharedPreferences preferences = getSharedPreferences("xujie,",MODE_PRIVATE);
        String value= preferences.getString("key", defaultValue);
        int value= preferences.getInt("key", defaultValue);
        ...
    }

存取使用SharedPreferences.Editor来完成。数据存储在/data/data/pageName/shared_prefs/perfer_file.xml里面,结构如下:


    value
    

注意点:
1.SharedPreferences对大小没有限制,但是如果存储数据过大会导致性能问题,因此要存储合理的数据。
2.SharedPreferences只能存储基本类型的数据。
3.SharedPreferences线程不安全。

4.ContentProvider

四大组件之一,数据通过ContentProvider存储在别的工程中。可参考四大组件文章。

5.网络存储

数据存储在网络上,通过Http等协议获取数据,常用库为Okhttp等。

你可能感兴趣的:(Android 文件存储)