一、對數據進行存儲,提供了openFileOutput() 方法 <數據的寫入>
/**
* 保存數據
* @param context
* @param fileName 保存文件名
* @param data 保存的數據
*/
public void saveFile(Context context, String fileName, String data) {
try {
FileOutputStream fos = context.openFileOutput(fileName, context.MODE_PRIVATE);
fos.write(data.getBytes());
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
openFileOutput(): 第一個參數是保存的文件名,如果不存在,android 會自動創建文件;
第二個參數是用於指定操作模式,有四種操作模式:
Context.MODE_PRIVATE = 0 //爲默認操作模式,代表該文件是私有數據,只能被應用本身訪問,在該模式下,寫入的內容會覆蓋原文件的內容
Context.MODE_APPEND = 32768 //會檢查文件是否存在,存在就往文件追加內容,否則就創建新文件。
Context.MODE_WORLD_READABLE = 1 //用來控制其他應用是否有權限讀該文件,表示當前文件可以被其他應用讀取
Context.MODE_WORLD_WRITEABLE = 2 //用來控制其他應用是否有權限寫該文件,表示當前文件可以被其他應用寫入
爲默認操作模式,代表該文件是私有數據,只能被應用本身訪問,在該模式下,寫入的內容會覆蓋原文件的內容
Context.MODE_APPEND = 32768 //會檢查文件是否存在,存在就往文件追加內容,否則就創建新文件。
Context.MODE_WORLD_READABLE = 1 //用來控制其他應用是否有權限讀該文件,表示當前文件可以被其他應用讀取
Context.MODE_WORLD_WRITEABLE = 2 //用來控制其他應用是否有權限寫該文件,表示當前文件可以被其他應用寫入
往sdcard 中存儲文件
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
File sdCardDir = Environment.getExternalStorageDirectory();//獲取SDCard目錄
File saveFile = new File(sdCardDir, "a.txt");
FileOutputStream outStream = new FileOutputStream(saveFile);
outStream.write("test".getBytes());
outStream.close();
}
二、對數據的讀取,FileInputStream <數據的讀取>
/**
* 讀取文件
* @param fileName 需要讀取的文件名
*/
public void readFile(String fileName) {
try {
FileInputStream fis = new FileInputStream(fileName); // 讀取數據 fileName 讀取的文件數據 .txt 等文件
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length = -1;
while ((length = fis.read(buffer)) != -1) {
// buffer : 寫入的數據; 0 : 寫入數據的開始位置 ; length : 每次寫入的bytes
baos.write(buffer, 0, length);
}
baos.close();
fis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
getCacheDir()方法用於獲取/data/data/<package name>/cache目錄
getFilesDir()方法用於獲取/data/data/<package name>/files目錄
三、對象輸入輸出流 ObjectInputStream ObjectOutputStream
對象的序列化以及反序列化。主要用於對象信息的寫入以及讀取。 對象信息一旦寫到文件上那麼對象的信息就可以做到持久化了
對象的輸出流ObjectOutputStream :將指定的對象寫入到文件的過程,就是將對象序列化的過程。(對象實現Serializable)
對象的輸入流ObjctInputStream : 指將指定序列化的對象讀出來的過程,就是將對象反序列化的過程。
1、對象的寫入
/**
* 將對象信息寫入到filePath文件中
* 定義方法把對象的信息寫到硬盤上------>對象的序列化。
*
* @param filePath 寫入對象信息的文件路徑
* @param object 寫入的對象
* @return
*/
public void saveObj(String filePath, Object object) {
File file = new File(filePath);
try {
FileOutputStream fos = new FileOutputStream(file); // 創建文件字節輸出流對象
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(object);
//最後記得關閉資源,oos.close()內部已經將fos對象資源釋放了,所以只需要關閉objectOutputStream即可
oos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
2、對象的讀取
/**
* 把文件中的對象信息讀取出來 —— 對象的反序列化過程
* @param filePath
*/
private void readObj(String filePath){
try {
FileInputStream fis = new FileInputStream(new File(filePath)); // 創建文件字節輸入流對象
ObjectInputStream ois = new ObjectInputStream(fis);
Object object = ois.readObject(); // 讀取文件後的對象
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
3、對象的寫入讀取可能存在的異常:
Exception in thread "main" java.io.InvalidClassException: xuliehua.User; local class incompatible: stream classdesc serialVersionUID = 2161776237447595412, local class serialVersionUID = -3634244984882257127
異常信息解讀:
serialVersionUID 是用於記錄class文件的版本信息的,serialVersionUID這個數字是JVM(JAVA虛擬界)通過一個類的類名、成員、包名、工程名算出的一個數字。而這時候序列化文件中記錄的serialVersionUID與項目中的不一致,即找不到對應的類來反序列化。
如果序列化與反序列化的時候可能會修改類的成員,那麼最好一開始就給這個類指定一個serialVersionUID,如果一類已經指定的serialVersionUID,然後在序列化與反序列化的時候,jvm都不會再自己算這個 class的serialVersionUID了。
不想要某些字段序列化時候,可以用transient關鍵字修飾
class Debug implements Serializable{
private static final long serialVersionUID = 1L;
private String debugInfo ;
private int debugId; // transient String debug; // 不需要序列化這個變量
public Debug(String debugInfo, int debugId) {
this.debugInfo = debugInfo;
this.debugId = debugId;
}
public String getDebugInfo() {
return debugInfo;
}
public void setDebugInfo(String debugInfo) {
this.debugInfo = debugInfo;
}
public int getDebugId() {
return debugId;
}
public void setDebugId(int debugId) {
this.debugId = debugId;
}
}
4、注意點:
1)對象的反序列化創建對象的時候並不會調用到構造方法的;
2)如果對象需要被寫出到文件上,那麼對象所屬的類必須要實現Serializable接口;
3)serialVersionUID 是用於記錄class文件的版本信息的,serialVersionUID這個數字是通過一個類的類名、成員、包名、工程名算出的一個數字;
4) 使用ObjectInputStream反序列化的時候,ObjeectInputStream會先讀取文件中的serialVersionUID,然後與本地的class文件的serialVersionUID進行對比,如果這兩個id不一致,反序列則失敗;
5) 如果序列化與反序列化的時候可能會修改類的成員,那麼最好一開始就給這個類指定一個serialVersionUID,如果一類已經指定的serialVersionUID,然後在序列化與反序列化的時候,jvm都不會再自己算這個 class的serialVersionUID了;
6)如果一個對象某個數據不想被序列化到硬盤上,可以使用關鍵字transient修飾;
7)如果一個類維護了另外一個類的引用,則另外一個類也需要實現Serializable接口。