1.IO文件讀取
IO流類圖
分類
按照讀取數(shù)據(jù)類型不同分為字節(jié)流
和字符流
按照數(shù)據(jù)流向不同分為輸入流
和```輸出流
常用方式
字節(jié)流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是帶緩沖區(qū)的輸入流舞萄,默認(rèn)緩沖區(qū)大小是8M,能夠減少訪問磁盤的次數(shù)澎办,提高文件讀取性能捂敌;BufferedOutputStream是帶緩沖區(qū)的輸出流蟹演,能夠提高文件的寫入效率阴颖。BufferedInputStream與BufferedOutputStream分別是FilterInputStream類和FilterOutputStream類的子類愤诱,實(shí)現(xiàn)了裝飾設(shè)計(jì)模式云头。
FileOutputStream outputStream = null;
BufferedOutputStream bufferedOutputStream;
try {
outputStream = new FileOutputStream(path);
bufferedOutputStream = new BufferedOutputStream(outputStream);
String str = "sssssssasdafafasda";
bufferedOutputStream.write(str.getBytes());
//寫完畢后要將數(shù)據(jù)刷新到文件中
bufferedOutputStream.flush();
outputStream.close();
bufferedOutputStream.close();
} //異常處理
FileInputStream inputStream = null;
BufferedInputStream bufferedInputStream;
try {
inputStream = new FileInputStream(file);
bufferedInputStream = new BufferedInputStream(inputStream);
StringBuilder builder = new StringBuilder();
//緩沖區(qū) 不設(shè)置默認(rèn)為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,帶緩沖區(qū)的字符流淫半。
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將字節(jié)流轉(zhuǎn)換為字符流
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 問題
虛擬機(jī)是否允許反序列化溃槐,不僅取決于類路徑和功能代碼是否一致,一個(gè)非常重要的一點(diǎn)是兩個(gè)類的序列化 ID 是否一致(就是 private static final long serialVersionUID = 1L)科吭。
2.靜態(tài)變量序列化
序列化保存的是對象的狀態(tài)昏滴,靜態(tài)變量屬于類的狀態(tài)猴鲫,因此 序列化并不保存靜態(tài)變量。
3.父類的序列化與 Transient 關(guān)鍵字
一個(gè)子類實(shí)現(xiàn)了 Serializable 接口谣殊,它的父類都沒有實(shí)現(xiàn) Serializable 接口拂共,序列化該子類對象,然后反序列化后輸出父類定義的某變量的數(shù)值姻几,該變量數(shù)值與序列化時(shí)的數(shù)值不同宜狐。
解決方法:要想將父類對象也序列化,就需要讓父類也實(shí)現(xiàn)Serializable 接口蛇捌「Ш悖或者有默認(rèn)的無參的構(gòu)造函數(shù),在構(gòu)造函數(shù)中完成初始化络拌。
Transient 關(guān)鍵字的作用是控制變量的序列化俭驮,在變量聲明前加上該關(guān)鍵字,可以阻止該變量被序列化到文件中春贸,在被反序列化后混萝,transient 變量的值被設(shè)為初始值,如 int 型的是 0萍恕,對象型的是 null逸嘀。
4.自定義序列化過程
虛擬機(jī)會試圖調(diào)用對象類里的 writeObject 和 readObject 方法,進(jìn)行用戶自定義的序列化和反序列化雄坪,如果沒有這樣的方法厘熟,則默認(rèn)調(diào)用是 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.序列化存儲規(guī)則
Java 序列化機(jī)制為了節(jié)省磁盤空間绳姨,具有特定的存儲規(guī)則,當(dāng)寫入文件的為同一對象時(shí)阔挠,并不會再將對象的內(nèi)容進(jìn)行存儲飘庄,而只是再次存儲一份引用,新增一些控制信息购撼。反序列化時(shí)跪削,恢復(fù)引用關(guān)系該存儲規(guī)則極大的節(jié)省了存儲空間。
2.sqlite數(shù)據(jù)庫
sqlite數(shù)據(jù)庫的使用:
1迂求、繼承SQLiteOpenHelper
public class DbHelper extends SQLiteOpenHelper {
//數(shù)據(jù)庫名稱
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) {
//上下文碾盐,數(shù)據(jù)庫名稱,游標(biāo)工廠揩局,版本號
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
//創(chuàng)建表操作
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) {
//更新操作一般有如下步驟毫玖,本次演示只默認(rèn)刪除重建
if (oldVersion != newVersion) {
//1.創(chuàng)建臨時(shí)表保存數(shù)據(jù)
//2.刪除現(xiàn)有表
//3.創(chuàng)建新表
//4.復(fù)制臨時(shí)表數(shù)據(jù)至新表
//5.刪除臨時(shí)表
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + dbTable);
onCreate(sqLiteDatabase);
}
}
}
2、創(chuàng)建數(shù)據(jù)庫操作類,持有SQLiteOpenHelper子類對象付枫,操作數(shù)據(jù)增刪改查:
//插入
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()){
//查詢數(shù)據(jù)
int id = query.getInt(query.getColumnIndex("Id"));
}
return builder.toString();
}
其余方法等同.數(shù)據(jù)庫詳細(xì)語法后續(xù)再詳細(xì)學(xué)習(xí)烹玉。
數(shù)據(jù)庫操作有兩種方式,一種如insert方法一樣執(zhí)行SQL語句阐滩,另一種如query方法一樣使用SQLiteDatabase 封裝過的方法二打。
sqlite是線程安全的嗎
Android中SQLiteDatabase為sqlite提供了線程安全的保證,因此Android中sqlite數(shù)據(jù)庫是線程安全的掂榔。
sqlite是線程安全的嗎
數(shù)據(jù)庫保存在/data/data/pageName/databases/dbName.db继效,其中pageName為包名,dbName為數(shù)據(jù)庫名稱衅疙。
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來完成鸳慈。數(shù)據(jù)存儲在/data/data/pageName/shared_prefs/perfer_file.xml里面饱溢,結(jié)構(gòu)如下:
<map>
<string name="key">value</string>
<int name="key" value="value" />
</map>
注意點(diǎn):
1.SharedPreferences對大小沒有限制,但是如果存儲數(shù)據(jù)過大會導(dǎo)致性能問題走芋,因此要存儲合理的數(shù)據(jù)绩郎。
2.SharedPreferences只能存儲基本類型的數(shù)據(jù)。
3.SharedPreferences線程不安全翁逞。
4.ContentProvider
四大組件之一肋杖,數(shù)據(jù)通過ContentProvider存儲在別的工程中⊥诤可參考四大組件文章状植。
5.網(wǎng)絡(luò)存儲
數(shù)據(jù)存儲在網(wǎng)絡(luò)上,通過Http等協(xié)議獲取數(shù)據(jù)怨喘,常用庫為Okhttp等津畸。