1.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();
}//异常处理
字符流操作文件
FileWriter与FileReader读写文件
//写文件
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里面,结构如下:
<map>
<string name="key">value</string>
<int name="key" value="value" />
</map>
注意点:
1.SharedPreferences对大小没有限制,但是如果存储数据过大会导致性能问题,因此要存储合理的数据。
2.SharedPreferences只能存储基本类型的数据。
3.SharedPreferences线程不安全。
4.ContentProvider
四大组件之一,数据通过ContentProvider存储在别的工程中。可参考四大组件文章。
5.网络存储
数据存储在网络上,通过Http等协议获取数据,常用库为Okhttp等。