Java笔记整理六(File类,递归,字节流IO,字符流IO,流中的异常处理,属性集Properties,缓冲流,转换流,序列化,打印流)
1.File類
java.io.File 類是文件和目錄路徑名的抽象表示,主要用于文件和目錄的創(chuàng)建、查找和刪除等操作。
文件和目錄路徑名的抽象表示
java把文件和文件夾封裝位為一個File類,我們可以用File類的對文件和文件夾進(jìn)行操作
使用File類我們可以
- 創(chuàng)建一個文件夾/文件
- 刪除文件/文件夾
- 獲取文件/文件夾
- 判斷文件/文件夾是否存在
- 獲取文件大小
File是一個與系統(tǒng)無關(guān)的類,任何系統(tǒng)都可以使用這個類中的方法。
重點(diǎn):
file:文件
directory:目錄
path:路徑
static String pathSeparator:路徑分隔符
static char pathSeparator:路徑分隔符
static String separator:默認(rèn)名稱分隔符
static char separator:默認(rèn)名稱分隔符
路徑不能寫死了
“c:“+File.separator+”develop“+File.separator+a.txt”
絕對路徑,相對路徑
絕對路徑:完整路徑c:\a.txt
相對路徑:簡化路徑,相對當(dāng)前項目的根目錄
注意:
File中的構(gòu)造方法
-
public File(String pathname) :通過將給定的路徑名字符串轉(zhuǎn)換為抽象路徑名來創(chuàng)建新的 File實(shí)例。
可以是以文件/文件夾結(jié)尾。可以相對路徑也可以是絕對路徑,可以是存在的也可以不存在。創(chuàng)建File對象,只把字符串路徑封裝給File對象,不考慮路徑對象 它重寫了File的toString方法。 -
public File(String parent, String child) :從父路徑名字符串和子路徑名字符串創(chuàng)建新的 File實(shí)例。
父路徑和子路徑,可以單獨(dú)書寫,使用靈活 -
public File(File parent, String child) :從父抽象路徑名和子路徑名字符串創(chuàng)建新的 File實(shí)例。
父路徑和子路徑,可以單獨(dú)書寫,使用靈活,父路徑是File類型,可以使用File的方法對路徑進(jìn)行一些操作,再使用路徑創(chuàng)建對象
獲取功能的方法
-
public String getAbsolutePath() :返回此File的絕對路徑名字符串。
-
public String getPath() :將此File轉(zhuǎn)換為路徑名字符串。
-
public String getName() :返回由此File表示的文件或目錄的名稱。
-
public long length() :返回由此File表示的文件的長度。
方法演示,代碼如下:
判斷功能的方法
- public boolean exists() :此File表示的文件或目錄是否實(shí)際存在。
- public boolean isDirectory() :此File表示的是否為目錄。
- public boolean isFile() :此File表示的是否為文件。
方法演示,代碼如下:
public class FileIs {public static void main(String[] args) {File f = new File("d:\\aaa\\bbb.java");File f2 = new File("d:\\aaa");// 判斷是否存在System.out.println("d:\\aaa\\bbb.java 是否存在:"+f.exists());System.out.println("d:\\aaa 是否存在:"+f2.exists());// 判斷是文件還是目錄System.out.println("d:\\aaa 文件?:"+f2.isFile());System.out.println("d:\\aaa 目錄?:"+f2.isDirectory());} } 輸出結(jié)果: d:\aaa\bbb.java 是否存在:true d:\aaa 是否存在:true d:\aaa 文件?:false d:\aaa 目錄?:true創(chuàng)建刪除功能的方法
-
public boolean createNewFile() :當(dāng)且僅當(dāng)具有該名稱的文件尚不存在時,創(chuàng)建一個新的空文件。 只能創(chuàng)建文件。不能創(chuàng)建文件夾。需要處理異常,必須路徑存在,否則會拋出io異常。
-
public boolean delete() :刪除由此File表示的文件或目錄。 不走回收站
-
文件/文件夾刪除成功,返回true
-
文件夾有內(nèi)容不回刪除,返回false,構(gòu)造方法中不存在也返回false
- public boolean mkdir() :創(chuàng)建由此File表示的目錄。只能創(chuàng)建單集空文件夾
- public boolean mkdirs() :創(chuàng)建由此File表示的目錄,包括任何必需但不存在的父目錄。可以創(chuàng)建單級文件夾也可以創(chuàng)建多級空文件夾。
- 返回值:true:文件夾不存在,創(chuàng)建文件夾,返回true
返回false:文件夾存在,不會創(chuàng)建,構(gòu)造方法中給出的路徑不存在也返回false
只能創(chuàng)建文件夾不能創(chuàng)建文件
創(chuàng)建文件的路徑必須存在,否則會拋出異常
方法演示,代碼如下:
public class FileCreateDelete {public static void main(String[] args) throws IOException {// 文件的創(chuàng)建File f = new File("aaa.txt");System.out.println("是否存在:"+f.exists()); // falseSystem.out.println("是否創(chuàng)建:"+f.createNewFile()); // trueSystem.out.println("是否存在:"+f.exists()); // true// 目錄的創(chuàng)建File f2= new File("newDir"); System.out.println("是否存在:"+f2.exists());// falseSystem.out.println("是否創(chuàng)建:"+f2.mkdir()); // trueSystem.out.println("是否存在:"+f2.exists());// true// 創(chuàng)建多級目錄File f3= new File("newDira\\newDirb");System.out.println(f3.mkdir());// falseFile f4= new File("newDira\\newDirb");System.out.println(f4.mkdirs());// true// 文件的刪除System.out.println(f.delete());// true// 目錄的刪除System.out.println(f2.delete());// trueSystem.out.println(f4.delete());// false} }API中說明:delete方法,如果此File表示目錄,則目錄必須為空才能刪除。
目錄的遍歷
-
public String[] list() :返回一個String數(shù)組,表示該File目錄中的所有子文件或目錄。把獲取到的多個名稱存儲到一個String類型的數(shù)組中。
-
public File[] listFiles() :返回一個File數(shù)組,表示該File目錄中的所有的子文件或目錄。遍歷構(gòu)造方法中給出的目錄,獲取所有文件或文件夾的名稱,把獲取到的多個名稱存儲到一個String類型的數(shù)組中
list和listFiles方法遍歷的是構(gòu)造方法中給出的目錄
如果走早方法中給出路徑不存在,會拋出空指針異常
如果構(gòu)造方法中給出的路徑不是一個目錄,會拋出空指針異常
小貼士:
調(diào)用listFiles方法的File對象,表示的必須是實(shí)際存在的目錄,否則返回null,無法進(jìn)行遍歷。
遞歸
遞歸:指再當(dāng)前方法體調(diào)用自己
分為直接遞歸和間接遞歸
注意事項:
- 遞歸一定要有條件限制,保證遞歸能夠停止
- 遞歸次數(shù)不能太多,否則可能會發(fā)生棧內(nèi)存溢出
- 構(gòu)造方法禁止遞歸
遞歸方法使用前提:
當(dāng)調(diào)用方法的時候,方法主體不變,每次調(diào)用方法的參數(shù)不同,可以使用遞歸
使用遞歸計算1–n的和
使用遞歸必須明確:
實(shí)現(xiàn)代碼:
public class DiGuiDemo {public static void main(String[] args) {//計算1~num的和,使用遞歸完成int num = 5;// 調(diào)用求和的方法int sum = getSum(num);// 輸出結(jié)果System.out.println(sum);}/*通過遞歸算法實(shí)現(xiàn).參數(shù)列表:int 返回值類型: int */public static int getSum(int num) {/* num為1時,方法返回1,相當(dāng)于是方法的出口,num總有是1的情況*/if(num == 1){return 1;}/*num不為1時,方法返回 num +(num-1)的累和遞歸調(diào)用getSum方法*/return num + getSum(num-1);} }遞歸求階乘
階乘:所有小于及等于該數(shù)的正整數(shù)的積。
n的階乘:n! = n * (n-1) *...* 3 * 2 * 1 推理得出:n! = n * (n-1)!代碼實(shí)現(xiàn):
public class DiGuiDemo {//計算n的階乘,使用遞歸完成public static void main(String[] args) {int n = 3;// 調(diào)用求階乘的方法int value = getValue(n);// 輸出結(jié)果System.out.println("階乘為:"+ value);}/*通過遞歸算法實(shí)現(xiàn).參數(shù)列表:int 返回值類型: int */public static int getValue(int n) {// 1的階乘為1if (n == 1) {return 1;}/*n不為1時,方法返回 n! = n*(n-1)!遞歸調(diào)用getValue方法*/return n * getValue(n - 1);} }遞歸打印多級目錄
分析:多級目錄的打印,就是當(dāng)目錄的嵌套。遍歷之前,無從知道到底有多少級目錄,所以我們還是要使用遞歸實(shí)現(xiàn)。
代碼實(shí)現(xiàn):
public class DiGuiDemo2 {public static void main(String[] args) {// 創(chuàng)建File對象File dir = new File("D:\\aaa");// 調(diào)用打印目錄方法printDir(dir);}public static void printDir(File dir) {// 獲取子文件和目錄File[] files = dir.listFiles();// 循環(huán)打印/*判斷:當(dāng)是文件時,打印絕對路徑.當(dāng)是目錄時,繼續(xù)調(diào)用打印目錄的方法,形成遞歸調(diào)用.*/for (File file : files) {// 判斷if (file.isFile()) {// 是文件,輸出文件絕對路徑System.out.println("文件名:"+ file.getAbsolutePath());} else {// 是目錄,輸出目錄絕對路徑System.out.println("目錄:"+file.getAbsolutePath());// 繼續(xù)遍歷,調(diào)用printDir,形成遞歸printDir(file);}}} }文件搜索
搜索D:\aaa 目錄中的.java 文件。
分析:
代碼實(shí)現(xiàn):
public class DiGuiDemo3 {public static void main(String[] args) {// 創(chuàng)建File對象File dir = new File("D:\\aaa");// 調(diào)用打印目錄方法printDir(dir);}public static void printDir(File dir) {// 獲取子文件和目錄File[] files = dir.listFiles();// 循環(huán)打印for (File file : files) {if (file.isFile()) {// 是文件,判斷文件名并輸出文件絕對路徑if (file.getName().endsWith(".java")) {System.out.println("文件名:" + file.getAbsolutePath());}} else {// 是目錄,繼續(xù)遍歷,形成遞歸printDir(file);}}} }文件過濾器優(yōu)化
listFiles(FileFilter fileter)
File類中有兩個和ListFiles重載的方法,方法參數(shù)就是過濾器
java.io.FileFilter是一個接口,是File的過濾器。 該接口的對象可以傳遞給File類的
用于抽象路徑名(File對象)的過濾器,用來過濾文件
boolean accept(File pathname) :測試pathname是否應(yīng)該包含在當(dāng)前File目錄中,符合則返回true。
listFiles(FilenameFilter fileter) :
java.io.FilenameFilter接口:實(shí)現(xiàn)此接口的類實(shí)例可用于過濾器文件名
用于過濾文件名稱
boolean accept(File dir ,String name) :測試文件是否包含在某一文件夾中
File dir:構(gòu)造方法中傳遞的被遍歷的目錄
String name::使用ListFiles方法遍歷目錄,獲取的每一個文件/文件夾的名稱
注意:兩個過濾器接口是沒有實(shí)現(xiàn)類的,需要我們自己寫實(shí)現(xiàn)類,重寫過濾方法accep,在方法中自己定義過濾器規(guī)則。
分析:
代碼實(shí)現(xiàn):
public class DiGuiDemo4 {public static void main(String[] args) {File dir = new File("D:\\aaa");printDir2(dir);}public static void printDir2(File dir) {// 匿名內(nèi)部類方式,創(chuàng)建過濾器子類對象File[] files = dir.listFiles(new FileFilter() {@Overridepublic boolean accept(File pathname) {return pathname.getName().endsWith(".java")||pathname.isDirectory();}});// 循環(huán)打印for (File file : files) {if (file.isFile()) {System.out.println("文件名:" + file.getAbsolutePath());} else {printDir2(file);}}} }FileFilter過濾器的原理和使用
必須明確兩件事情:
ListFiles方法一共做了三件事情:
accept方法返回的是一個boolean值
true: 會把傳遞過去的File對象保存到File數(shù)組中
false:就不會把傳遞過去的File對象保存到File數(shù)組中
因此,過濾的規(guī)則:
在accept方法中,判斷File對象
Lambda優(yōu)化
分析:FileFilter是只有一個方法的接口,因此可以用lambda表達(dá)式簡寫。
lambda格式:
()->{ }代碼實(shí)現(xiàn):
public static void printDir3(File dir) {// lambda的改寫File[] files = dir.listFiles(f ->{ return f.getName().endsWith(".java") || f.isDirectory(); });// 循環(huán)打印for (File file : files) {if (file.isFile()) {System.out.println("文件名:" + file.getAbsolutePath());} else {printDir3(file);}} }IO
IO的分類
根據(jù)數(shù)據(jù)的流向分為:輸入流和輸出流。
- 輸入流 :把數(shù)據(jù)從其他設(shè)備上讀取到內(nèi)存中的流。
- 輸出流 :把數(shù)據(jù)從內(nèi)存 中寫出到其他設(shè)備上的流。
格局?jǐn)?shù)據(jù)的類型分為:字節(jié)流和字符流。
- 字節(jié)流 :以字節(jié)為單位,讀寫數(shù)據(jù)的流。
- 字符流 :以字符為單位,讀寫數(shù)據(jù)的流。
流:數(shù)據(jù)(字符,字節(jié))一個字符=兩個字節(jié)
一個字節(jié)=八個二進(jìn)制(八位)
| 字節(jié)流 | 字節(jié)輸入流 InputStream | 字節(jié)輸出流 OutputStream |
| 字符流 | 字符輸入流 Reader | 字符輸出流 Writer |
IO字節(jié)流
以二進(jìn)制數(shù)字的形式保存,都一個一個的字節(jié),那么傳輸時一樣如此
字節(jié)輸出流OutputStream
java.io.OutputStream抽象類是表示字節(jié)輸出流的所有類的超類,將指定的字節(jié)信息寫出到目的地。它定義了字節(jié)輸出流的基本共性功能方法。
- public void close() :關(guān)閉此輸出流并釋放與此流相關(guān)聯(lián)的任何系統(tǒng)資源。
- public void flush() :刷新此輸出流并強(qiáng)制任何緩沖的輸出字節(jié)被寫出。
- public void write(byte[] b):將 b.length字節(jié)從指定的字節(jié)數(shù)組寫入此輸出流。
- public void write(byte[] b, int off, int len) :從指定的字節(jié)數(shù)組寫入 len字節(jié),從偏移量 off開始輸出到此輸出流。
- public abstract void write(int b) :將指定的字節(jié)輸出流。
close方法,當(dāng)完成流的操作時,必須調(diào)用此方法,釋放系統(tǒng)資源。
FileOutputStream類:文件輸出流
java.io.FileOutputStream類是文件輸出流,用于將內(nèi)存數(shù)據(jù)寫出到硬盤的文件中。
構(gòu)造方法
- public FileOutputStream(File file):創(chuàng)建文件輸出流以寫入由指定的 File對象表示的文件。
- public FileOutputStream(String name): 創(chuàng)建文件輸出流以指定的名稱寫入文件。
參數(shù):寫入數(shù)據(jù)的目的地。
String name文件路徑
File file:目的地是一個文件
構(gòu)造方法地作用:
1.創(chuàng)建一個 FileOutputStream對象
2.會根據(jù)構(gòu)造方法中傳遞的文件/文件路徑,創(chuàng)建一個空的文件
3.會把 FileOutputStream對象指向創(chuàng)建好的問文件
字節(jié)流寫入數(shù)據(jù)到文件
寫出字節(jié)
寫入數(shù)據(jù)的原理:(內(nèi)存–>硬盤)
java程序—>JVM(Java虛擬機(jī))—>Os(操作系統(tǒng))—>OS調(diào)用寫數(shù)據(jù)的方法—>把數(shù)據(jù)寫入到文件中
字節(jié)輸出流的使用步驟:
需要拋出異常
public class FOSWrite {public static void main(String[] args) throws IOException {// 使用文件名稱創(chuàng)建流對象FileOutputStream fos = new FileOutputStream("fos.txt"); // 寫出數(shù)據(jù)fos.write(97); // 寫出第1個字節(jié)fos.write(98); // 寫出第2個字節(jié)fos.write(99); // 寫出第3個字節(jié)// 關(guān)閉資源fos.close();} } 輸出結(jié)果: abc寫數(shù)據(jù)的時候,會把10進(jìn)制的整數(shù)轉(zhuǎn)換為二進(jìn)制整數(shù)97
當(dāng)你創(chuàng)建一個流對象時,必須傳入一個文件路徑。該路徑下,如果沒有這個文件,會創(chuàng)建該文件。如果有這個文件,會清空這個文件的數(shù)據(jù)。
寫出字節(jié)數(shù)組:write(byte[] b),
一次寫多個字節(jié)
寫出指定長度字節(jié)數(shù)組:write(byte[] b, int off, int len) ,每次寫出從off索引開始,len個字節(jié)。把字節(jié)數(shù)組的一部寫入到文件中
.getBytes()把字符串轉(zhuǎn)換為字節(jié)數(shù)組
arrays.toString(字節(jié)數(shù)組)轉(zhuǎn)換為十進(jìn)制數(shù)組
數(shù)據(jù)追加續(xù)寫
** 追加寫**:使用兩個參數(shù)的構(gòu)造方法
-
public FileOutputStream(File file, boolean append): 創(chuàng)建文件輸出流以寫入由指定的 File對象表示的文件。
-創(chuàng)建一個向指定File對象表示的文件中寫入數(shù)據(jù)的文件輸出流 -
public FileOutputStream(String name, boolean append): 創(chuàng)建文件輸出流以指定的名稱寫入文件
-
創(chuàng)建一個向具有指定name的文件中寫入數(shù)據(jù)的輸出文件流
String 那么,File file:寫入數(shù)據(jù)的目的地
boolean append:追加寫開關(guān)
true:創(chuàng)建對象不回覆蓋原文件,繼續(xù)在文件的末尾追加寫數(shù)據(jù)
false:創(chuàng)建一個新文件,覆蓋原文件
寫換行:寫換行符號
windows:\r\n
linux: /n
mac:/r
字節(jié)輸入流InputStream
java.io.InputStream抽象類是表示字節(jié)輸入流的所有類的超類,可以讀取字節(jié)信息到內(nèi)存中。它定義了字節(jié)輸入流的基本共性功能方法。
所有子類共性的方法:
-
public void close() :關(guān)閉此輸入流并釋放與此流相關(guān)聯(lián)的任何系統(tǒng)資源。
-
public abstract int read(): 從輸入流讀取數(shù)據(jù)的下一個字節(jié)。
-
public int read(byte[] b): 從輸入流中讀取一些字節(jié)數(shù),并將它們存儲到字節(jié)數(shù)組 b中 。
close方法,當(dāng)完成流的操作時,必須調(diào)用此方法,釋放系統(tǒng)資源。
FileInputStream類
作用:把硬盤中的文件數(shù)據(jù),讀取到內(nèi)存中使用
構(gòu)造方法:
-
FileInputStream(File file): 通過打開與實(shí)際文件的連接來創(chuàng)建一個 FileInputStream ,該文件由文件系統(tǒng)中的 File對象 file命名。
-
FileInputStream(String name): 通過打開與實(shí)際文件的連接來創(chuàng)建一個 FileInputStream ,該文件由文件系統(tǒng)中的路徑名 name命名。
當(dāng)你創(chuàng)建一個流對象時,必須傳入一個文件路徑。該路徑下,如果沒有該文件,會拋出FileNotFoundException 。
參數(shù):讀取文件的數(shù)據(jù)源
String name:文件路徑
File file:文件
構(gòu)造方法的作用:
1.會創(chuàng)建一個FileInputStream對象
2.會把FileInputStream對象指定給構(gòu)造方法中讀取的文件
讀取數(shù)據(jù)的原理(硬盤–>內(nèi)存)
java程序 -->JVM -->OS–>OS讀取數(shù)據(jù)的方法–>讀取文件
自己輸入流的使用步驟(重點(diǎn)):
讀取字節(jié)數(shù)據(jù)
每次讀取一個字節(jié)
public class FISRead {public static void main(String[] args) throws IOException{// 使用文件名稱創(chuàng)建流對象FileInputStream fis = new FileInputStream("read.txt");// 讀取數(shù)據(jù),返回一個字節(jié)int read = fis.read();System.out.println((char) read);read = fis.read();System.out.println((char) read);read = fis.read();System.out.println((char) read);read = fis.read();System.out.println((char) read);read = fis.read();System.out.println((char) read);// 讀取到末尾,返回-1read = fis.read();System.out.println( read);// 關(guān)閉資源fis.close();} } 輸出結(jié)果: a b c d e -1循環(huán)改進(jìn)讀取方式,代碼使用演示:
不知道文件有多少字節(jié),使用while循環(huán)
結(jié)束條件:讀取到-1的時候
. 使用字節(jié)數(shù)組讀取:read(byte[] b),每次讀取b的長度個字節(jié)到數(shù)組中,返回讀取到的有效字節(jié)個數(shù),讀取到末尾時,返回-1 ,:
public class FISRead {public static void main(String[] args) throws IOException{// 使用文件名稱創(chuàng)建流對象.FileInputStream fis = new FileInputStream("read.txt"); // 文件中為abcde// 定義變量,作為有效個數(shù)int len ;// 定義字節(jié)數(shù)組,作為裝字節(jié)數(shù)據(jù)的容器 byte[] b = new byte[2];// 循環(huán)讀取while (( len= fis.read(b))!=-1) {// 每次讀取后,把數(shù)組的有效字節(jié)部分,變成字符串打印System.out.println(new String(b,0,len));// len 每次讀取的有效字節(jié)個數(shù)}// 關(guān)閉資源fis.close();} }輸出結(jié)果: ab cd e一次讀取多個字節(jié)
原理:
1.創(chuàng)建一個流對象,并把它指向要讀取的文件
2.創(chuàng)建一個byte數(shù)組
3.讀取數(shù)據(jù)
- 讀取數(shù)組長度大小的數(shù)據(jù)
- 返回有效讀取字節(jié)個數(shù)
數(shù)組起到緩沖作用,存儲讀取到的多個字節(jié) 一般定義為1024的整數(shù)倍
字節(jié)流練習(xí):圖片復(fù)制
文件復(fù)制:一讀一寫
明確:
數(shù)據(jù)源
數(shù)據(jù)的目的地:
字符流
當(dāng)使用字節(jié)流讀取文本文件時,可能會有一個小問題。就是遇到中文字符時,可能不會顯示完整的字符,那是因為一個中文字符可能占用多個字節(jié)存儲。所以Java提供一些字符流類,以字符為單位讀寫數(shù)據(jù),專門用于處理文本文件。
GBK:占用兩個字節(jié)
utf-8:占用三個字節(jié)
字符輸入流【Reader】
java.io.Reader抽象類是表示用于讀取字符流的所有類的超類,可以讀取字符信息到內(nèi)存中。它定義了字符輸入流的基本共性功能方法。
共有成員方法
- public int read(): 從輸入流讀取一個字符。
- public int read(char[] cbuf): 從輸入流中讀取多個字符,并將它們存儲到字符數(shù)組 cbuf中 。
- public void close() :關(guān)閉此流并釋放與此流相關(guān)聯(lián)的任何系統(tǒng)資源。
FileReader類 文件字符輸入流
java.io.FileReaderextend InputStreamReader··extendReader類
是讀取字符文件的便利類。構(gòu)造時使用系統(tǒng)默認(rèn)的字符編碼和默認(rèn)字節(jié)緩沖區(qū)。
作用:把硬盤中的數(shù)據(jù)以字符的方式讀取到內(nèi)存中
構(gòu)造方法:
- FileReader(File file): 創(chuàng)建一個新的 FileReader ,給定要讀取的File對象。
- FileReader(String fileName): 創(chuàng)建一個新的 FileReader ,給定要讀取的文件的名稱。
參數(shù):讀取的數(shù)據(jù)源
String fileName:文件的路徑
File file:文件
FileReader構(gòu)造方法中的作用:
1.創(chuàng)建一個FileReader的對象
2.會把FileReader對象指向要讀取的文件
當(dāng)你創(chuàng)建一個流對象時,必須傳入一個文件路徑。類似于FileInputStream 。
字符編碼:字節(jié)與字符的對應(yīng)規(guī)則。Windows系統(tǒng)的中文編碼默認(rèn)是GBK編碼表。
idea中UTF-8
字節(jié)緩沖區(qū):一個字節(jié)數(shù)組,用來臨時存儲字節(jié)數(shù)據(jù)。
字符輸入流的使用步驟?
1.創(chuàng)建FileReader對象,構(gòu)造方法中要綁定要讀取的數(shù)據(jù)源
2.使用FileReader對象中的方法Read讀取文件
3.釋放資源
讀取字符數(shù)據(jù)
使用字符數(shù)組讀取:read(char[] cbuf),每次讀取b的長度個字符到數(shù)組中,返回讀取到的有效字符個數(shù),讀取到末尾時,返回-1 ,代碼使用演示:
String類構(gòu)造方法:
String(char[] value):把字符數(shù)組轉(zhuǎn)換為字符串
String(char[] value,int offset ,int count):把字符數(shù)組一部分轉(zhuǎn)換為字符串
獲取有效的字符改進(jìn),代碼使用演示:
public class FISRead {public static void main(String[] args) throws IOException {// 使用文件名稱創(chuàng)建流對象FileReader fr = new FileReader("read.txt");// 定義變量,保存有效字符個數(shù)int len ;// 定義字符數(shù)組,作為裝字符數(shù)據(jù)的容器char[] cbuf = new char[2];// 循環(huán)讀取while ((len = fr.read(cbuf))!=-1) {System.out.println(new String(cbuf,0,len));}// 關(guān)閉資源fr.close();} }輸出結(jié)果: 黑馬 程序 員字符輸出流【W(wǎng)riter】
java.io.Writer抽象類是表示用于寫出字符流的所有類的超類,將指定的字符信息寫出到目的地。它定義了字節(jié)輸出流的基本共性功能方法。
- void write(int c) 寫入單個字符。
- void write(char[] cbuf)寫入字符數(shù)組。
- abstract void write(char[] cbuf, int off, int len)寫入字符數(shù)組的某一部分,off數(shù)組的開始索引,len寫的字符個數(shù)。
- void write(String str)寫入字符串。
- void write(String str, int off, int len) 寫入字符串的某一部分,off字符串的開始索引,len寫的字符個數(shù)。
- void flush()刷新該流的緩沖。
- void close() 關(guān)閉此流,但要先刷新它。
FileWriter類 文件字符輸出流
作用: 把內(nèi)存中的字符數(shù)數(shù)劇寫入到文件中
java.io.FileWriterextends OutputStreamWrite extends··Write
java.io.FileWriter類是寫出字符到文件的便利類。構(gòu)造時使用系統(tǒng)默認(rèn)的字符編碼和默認(rèn)字節(jié)緩沖區(qū)。
構(gòu)造方法:
- FileWriter(File file): 創(chuàng)建一個新的 FileWriter,給定要讀取的File對象。
- FileWriter(String fileName): 創(chuàng)建一個新的 FileWriter,給定要讀取的文件的名稱。
當(dāng)你創(chuàng)建一個流對象時,必須傳入一個文件路徑,類似于FileOutputStream。
參數(shù):寫入文件的目的地
String fileName:文件的路徑
File file:文件
構(gòu)造方法中的作用:
字符輸出流的使用步驟:
基本寫出數(shù)據(jù)
寫出單個字符:write(int b) 方法,每次可以寫出一個字符數(shù)據(jù),代碼使用演示:
public class FWWrite {public static void main(String[] args) throws IOException {// 使用文件名稱創(chuàng)建流對象FileWriter fw = new FileWriter("fw.txt"); // 寫出數(shù)據(jù)fw.write(97); // 寫出第1個字符fw.write('b'); // 寫出第2個字符fw.write('C'); // 寫出第3個字符fw.write(30000); // 寫出第4個字符,中文編碼表中30000對應(yīng)一個漢字。/*【注意】關(guān)閉資源時,與FileOutputStream不同。如果不關(guān)閉,數(shù)據(jù)只是保存到緩沖區(qū),并未保存到文件。*/// fw.close();} } 輸出結(jié)果: abC田關(guān)閉和刷新
因為內(nèi)置緩沖區(qū)的原因,如果不關(guān)閉輸出流,無法寫出字符到文件中。但是關(guān)閉的流對象,是無法繼續(xù)寫出數(shù)據(jù)的。如果我們既想寫出數(shù)據(jù),又想繼續(xù)使用流,就需要flush 方法了。
- flush :刷新緩沖區(qū),流對象可以繼續(xù)使用。
- close:先刷新緩沖區(qū),然后通知系統(tǒng)釋放資源。流對象不可以再被使用了。
寫出其他數(shù)據(jù)
使用兩個參數(shù)的構(gòu)造方法:
FileWriter(String fileName,Boolean append)
FileWriter(File file,Boolean append)
Boolean append:
true:可以續(xù)寫,不回創(chuàng)建新的文件覆蓋源文件
false:創(chuàng)建新的文件覆蓋源文件
流中的異常處理
jdk1.7之前使用try...catch...finally處理流中的異常
public class HandleException1 {public static void main(String[] args) {// 聲明變量,提高變量作用域,聲明時可以沒有值,使用時必須有值FileWriter fw = null;try {//可能會出現(xiàn)異常的代碼創(chuàng)建流對象fw = new FileWriter("fw.txt");// 寫出數(shù)據(jù)fw.write("黑馬程序員"); //黑馬程序員} catch (IOException e) {//異常的處理邏輯e.printStackTrace();} finally {try { //若創(chuàng)建對象失敗,fw默認(rèn)值時null,null不能調(diào)用方法,會拋出nullponitException,需要增加一個判斷不是null,則釋放資源if (fw != null) {fw.close();}} catch (IOException e) {e.printStackTrace();}}} }JDK7的新特性:
在try之后增加一個();
在括號中可以定義流對象,那么這個流對象的作用域就在try中有效,try中代碼執(zhí)行完畢,會自動把流對象釋放掉,不用寫finally,
格式如下:
代碼使用演示:
public class HandleException2 {public static void main(String[] args) {// 創(chuàng)建流對象try ( FileWriter fw = new FileWriter("fw.txt"); ) {// 寫出數(shù)據(jù)fw.write("黑馬程序員"); //黑馬程序員} catch (IOException e) {e.printStackTrace();}} }JDK9的改進(jìn)(擴(kuò)展知識點(diǎn)了解內(nèi)容)
try的前邊可以定義流對象
在try后邊()中可以直接引入流對象的名稱(變量名)
在try代碼執(zhí)行完畢之后流對象也可以釋放掉,不用寫finally
JDK9中try-with-resource 的改進(jìn),對于引入對象的方式,支持的更加簡潔。被引入的對象,同樣可以自動關(guān)閉,無需手動close,我們來了解一下格式。
A a =new A();
B b=new B();
try(a,b){
可能會產(chǎn)出異常的代碼,
} catch(異常類變量 變量名){
異常的處理邏輯
}
屬性集
概述
java.util.Properties 繼承于Hashtable ,來表示一個持久的屬性集。它使用鍵值結(jié)構(gòu)存儲數(shù)據(jù),每個鍵及其對應(yīng)值都是一個字符串。該類也被許多Java類使用,比如獲取系統(tǒng)屬性時,System.getProperties 方法就是返回一個Properties對象。
java.util.Properties extends hashtable<K,v>implements Map<K,v>
Properties類
表示了一個持久的屬性集Properties可保存在流中或從流中加載。
Properties集合是唯一一個和IO流相結(jié)合的集合
可以使用Properties集合中的臨時數(shù)據(jù),持久化寫入到硬盤中存儲、
可以使用Properties集合中的方法load,把硬盤中保存的文件(鍵值對),讀取到集合中使用
Properties屬性列表中每個鍵及其對對應(yīng)的值都是一個字符串
Properties是一個雙列集合,key和value默認(rèn)都是字符串
構(gòu)造方法
- public Properties() :創(chuàng)建一個空的屬性列表。
基本的存儲方法
使用Properties結(jié)合存儲數(shù)據(jù),遍歷取出Properties集合中的數(shù)據(jù)
是一個雙列集合,Key和value都是字符串
- public Object setProperty(String key, String value) : 保存一對屬性。 調(diào)用hashtable的方法put
- public String getProperty(String key) :使用此屬性列表中指定的鍵搜索屬性值。通過key找到value值,此方法相當(dāng)于map集合中的get(key)方法
- public Set<String> stringPropertyNames() :所有鍵的名稱的集合。返回此屬性列表中的鍵集,其中該鍵及其對應(yīng)值是字符串,此方法相當(dāng)于Map集合中的KeySet方法
與流相關(guān)的方法
可以使用properties集合中的方法store,把集合中的臨時數(shù)據(jù),持久化寫入到硬盤中存儲
void store (OutputStream out,String comments)
void store(Write write,String comments)
參數(shù):
OutputStream out:不可以寫入中文
Write write:字符輸出流,可以寫入中文
String comments:注釋,用來解釋說明保存的文件是做什么用的,不能使用中文,會產(chǎn)生亂碼默認(rèn)unicide編碼,一般使用“空字符串”
使用步驟:
可以使用Properties集合中的方法load,把硬盤中保存的文件(鍵值對),讀取到集合中使用
- public void load(InputStream inStream): 從字節(jié)輸入流中讀取鍵值對。
- public void load(Reader reader):
參數(shù):
(InputStream inStream):字節(jié)輸入流,不能讀取含有中文的鍵值對,
Reader reader:字符輸入流,可以讀取含有中文的鍵值對
通過流對象,可以關(guān)聯(lián)到某文件上,這樣就能夠加載文本中的數(shù)據(jù)了。文本數(shù)據(jù)格式:
使用步驟:
注意:
加載代碼演示:
一般使用字符流
小貼士:文本中的數(shù)據(jù),必須是鍵值對形式,可以使用空格、等號、冒號等符號分隔。
緩沖流,也叫高效流,是對4個基本的FileXxx 流的增強(qiáng),所以也是4個流,按照數(shù)據(jù)類型分類:
緩沖流
緩沖流的基本原理,是在創(chuàng)建流對象時,會創(chuàng)建一個內(nèi)置的默認(rèn)大小的緩沖區(qū)數(shù)組,通過緩沖區(qū)讀寫,減少系統(tǒng)IO次數(shù),從而提高讀寫的效率。
字節(jié)緩沖流
BufferedInputStream,字節(jié)緩沖輸入流
所有子類共性的方法:
-
public void close() :關(guān)閉此輸入流并釋放與此流相關(guān)聯(lián)的任何系統(tǒng)資源。
-
public abstract int read(): 從輸入流讀取數(shù)據(jù)的下一個字節(jié)。
-
public int read(byte[] b): 從輸入流中讀取一些字節(jié)數(shù),并將它們存儲到字節(jié)數(shù)組 b中 。
close方法,當(dāng)完成流的操作時,必須調(diào)用此方法,釋放系統(tǒng)資源。
BufferedOutputStream 字節(jié)緩沖輸出流
共性方法:
- public void close() :關(guān)閉此輸出流并釋放與此流相關(guān)聯(lián)的任何系統(tǒng)資源。
- public void flush() :刷新此輸出流并強(qiáng)制任何緩沖的輸出字節(jié)被寫出。
- public void write(byte[] b):將 b.length字節(jié)從指定的字節(jié)數(shù)組寫入此輸出流。
- public void write(byte[] b, int off, int len) :從指定的字節(jié)數(shù)組寫入 len字節(jié),從偏移量 off開始輸出到此輸出流。
- public abstract void write(int b) :將指定的字節(jié)輸出流。
close方法,當(dāng)完成流的操作時,必須調(diào)用此方法,釋放系統(tǒng)資源。
字節(jié)緩沖輸入流
構(gòu)造方法
- public BufferedInputStream(InputStream in) :創(chuàng)建一個 新的緩沖輸入流。 ,保存其參數(shù),即輸入流in,以便將來使用
- public BufferedInputStream(InputStream in,int size ) :創(chuàng)建一個 具有指定緩沖區(qū)大小的緩沖輸入流,并保存其參數(shù)
參數(shù):
InputStream in字節(jié)輸入流:我們可以傳遞FileInputStream,增加一個緩沖區(qū),提高FileInputStream的讀取效率
int size:指定緩沖流內(nèi)部緩沖區(qū)大小,不指定默認(rèn)
使用步驟
1.創(chuàng)建FileInputStream對象,構(gòu)造方法中綁定要讀取的數(shù)據(jù)源
2.創(chuàng)建BufferedInputStream對象,構(gòu)造方法中傳遞FileInputStream對象,提高FileInputStream對象效率
3.使用BufferedInputStream對象中的方法read ,讀取文件
4.釋放資源(會調(diào)用Flue方法刷新數(shù)據(jù))
字節(jié)緩沖輸出流
-
public BufferedOutputStream(OutputStream out): 創(chuàng)建一個新的緩沖輸出流。以將數(shù)據(jù)寫入指定的底層輸出流
-
public BufferedOutputStream(OutputStream out,int size): 創(chuàng)建一個新的緩沖輸出流。以將數(shù)據(jù)寫入指定的底層輸出流
參數(shù):
OutputStream out:字節(jié)輸出流
我們可以傳遞FileOutputStream,緩沖流會給FileOutoutStream增加一個緩沖區(qū),提高FileOutputStream 的寫入效率
使用步驟:
1.創(chuàng)建FileOutputStream對象,構(gòu)造方法中綁定要輸出目的地
2.創(chuàng)建BufferedOutputStream對象,構(gòu)造方法中傳遞FileOutputStream對象 對象,提高FileOutputStream對象效率
3.使用BufferedOutputStream對象中的方法write,把數(shù)據(jù)寫入到內(nèi)部緩沖區(qū),
4.使用BufferedOutputStream對象中的方法flush把內(nèi)部緩沖區(qū)中的數(shù)據(jù),刷新到文件中
5.釋放資源(會調(diào)用Flue方法刷新數(shù)據(jù))
構(gòu)造舉例,代碼如下:
// 創(chuàng)建字節(jié)緩沖輸入流 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bis.txt")); // 創(chuàng)建字節(jié)緩沖輸出流 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));關(guān)閉緩沖流,會自動關(guān)閉基本流
效率測試
如何更快呢?
使用數(shù)組的方式,代碼如下:
public class BufferedDemo {public static void main(String[] args) throws FileNotFoundException {// 記錄開始時間long start = System.currentTimeMillis();// 創(chuàng)建流對象try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("jdk9.exe"));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.exe"));){// 讀寫數(shù)據(jù)int len;byte[] bytes = new byte[8*1024];while ((len = bis.read(bytes)) != -1) {bos.write(bytes, 0 , len);}} catch (IOException e) {e.printStackTrace();}// 記錄結(jié)束時間long end = System.currentTimeMillis();System.out.println("緩沖流使用數(shù)組復(fù)制時間:"+(end - start)+" 毫秒");} } 緩沖流使用數(shù)組復(fù)制時間:666 毫秒字符緩沖流
共性方法
- void write(int c) 寫入單個字符。
- void write(char[] cbuf)寫入字符數(shù)組。
- abstract void write(char[] cbuf, int off, int len)寫入字符數(shù)組的某一部分,off數(shù)組的開始索引,len寫的字符個數(shù)。
- void write(String str)寫入字符串。
- void write(String str, int off, int len) 寫入字符串的某一部分,off字符串的開始索引,len寫的字符個數(shù)。
- void flush()刷新該流的緩沖。
- void close() 關(guān)閉此流,但要先刷新它。
BufferedWriter字符緩沖輸出流
構(gòu)造方法
BufferedWriter(writer out):創(chuàng)建一個使用默認(rèn)大小輸出緩沖區(qū)的緩沖輸出流
BufferedWriter(writer out,int sz):創(chuàng)建一個使用給定大小輸出緩沖區(qū)的新緩沖字符輸出流
參數(shù):
writer out:字符輸出流
我們可以傳遞一個FileWriter,緩沖流會給FileWriter增加一個緩沖區(qū),提高FileWrite的寫入效率
int sz:指定緩沖區(qū)的大小,不寫默認(rèn)大小
特有成員方法:
Void newLine():寫入一個分隔符,會根據(jù)不同的操作系統(tǒng),獲取不同的行分隔符
換行符號:
windows:\r\n
linux:/n
mac:/r
使用步驟:
1.創(chuàng)建字符緩沖輸出流對象,構(gòu)造方法中傳遞字符輸出流
2.調(diào)用字符緩沖流中的方法,write,把數(shù)據(jù)寫入到內(nèi)存緩沖區(qū)中
3.調(diào)用字符緩沖流中的方法flush,把內(nèi)存緩沖區(qū)中的數(shù)據(jù),刷新到文件中
4.釋放資源
BufferedReader,extends Reader 字符緩沖輸入流
- 共有成員方法
- public int read(): 從輸入流讀取一個字符。
- public int read(char[] cbuf): 從輸入流中讀取多個字符,并將它們存儲到字符數(shù)組 cbuf中 。
- public void close() :關(guān)閉此流并釋放與此流相關(guān)聯(lián)的任何系統(tǒng)資源。
構(gòu)造方法
BufferedReader(Reader in):創(chuàng)建一個使用默認(rèn)大小的輸出緩沖的緩沖字符輸入流
BufferedReader(Reader in,int sz):創(chuàng)建一個使用指定大小的緩沖區(qū)的緩沖字符輸入流
參數(shù)
Reader in:字符輸入流我們可以傳遞FileReader,緩沖流會給FileReader增加一個緩沖區(qū),提高FileReader的讀取效率
int sz:
特有成員方法
String readLine():讀取一個文本行 。讀一行數(shù)據(jù),行的終止符號:通過列字符之一即可認(rèn)為某行已終止,換行\(zhòng)n 回車\r,回車后跟著換行(\r\n)
返回值:包含該行內(nèi)容字符串,不包含任何行終止符,如果已到達(dá)流末尾,則返回null
使用步驟
readLine方法演示,代碼如下:
1.4 練習(xí):文本排序
練習(xí):
對文本的內(nèi)容進(jìn)行排序
案例分析
1.創(chuàng)建一個HashMap集合對象,可以存儲每行文本的序號,value存儲每行的文本
2.創(chuàng)建字符緩沖輸入流對象,構(gòu)造方法綁定字符輸入流
3.創(chuàng)建字符緩沖輸出流對象,構(gòu)造方法中綁定字符輸出流
4.使用字符緩沖輸入流的方法readLine,逐行讀取文本
5.對讀取到的文本 進(jìn)行切割,獲取行中的序號和文本內(nèi)容
6.把切割好的序號和文本的內(nèi)容存儲到Hashmap集合中(key序號是有序的,會自動排序)
7.遍歷HashMap集合,獲取每一個鍵值對
8.把每一個鍵值對拼接為一個文本行
9.把拼接好的文本,使用字符緩沖輸出流中的方法write,寫入到文件中
10.釋放資源
案例實(shí)現(xiàn)
public class BufferedTest {public static void main(String[] args) throws IOException {//1. 創(chuàng)建map集合,保存文本數(shù)據(jù),鍵為序號,值為文字HashMap<String, String> lineMap = new HashMap<>();// 2.創(chuàng)建字符緩沖輸入流對象,構(gòu)造方法中綁定字符輸入流BufferedReader br = new BufferedReader(new FileReader("in.txt"));//3.創(chuàng)建一個字符緩沖輸出流對象,構(gòu)造方法中綁定字符串輸出流BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt")); //4.使用字符緩沖輸出流中的方法readLine逐行讀取文本// 讀取數(shù)據(jù)String line = null;while ((line = br.readLine())!=null) {// 解析文本String[] split = line.split("\\.");// 保存到集合lineMap.put(split[0],split[1]);}// 釋放資源br.close();// 遍歷map集合for (int i = 1; i <= lineMap.size(); i++) {String key = String.valueOf(i);// 獲取map中文本String value = lineMap.get(key);// 寫出拼接文本bw.write(key+"."+value);// 寫出換行bw.newLine();}// 釋放資源bw.close();} }轉(zhuǎn)換流
字符編碼和字符集
按照某種規(guī)則,將字符存儲到計算機(jī)中,稱為編碼 。反之,將存儲在計算機(jī)中的二進(jìn)制數(shù)按照某種規(guī)則解析顯示出來,稱為解碼 。
字符編碼:就是一套自然語音字符與二進(jìn)制數(shù)之間的對應(yīng)規(guī)則
字符集:也叫編碼表,是一個系統(tǒng)支持所有字符的集合
Idea默認(rèn)編碼utf-8
FileReader可以讀取IO默認(rèn)編碼格式UTF-8的文件
FileReader讀取系統(tǒng)默認(rèn)編碼GBK中文 會產(chǎn)生亂碼
InputStreamReader類
轉(zhuǎn)換流java.io.InputStreamReader,是Reader的子類,是從字節(jié)流到字符流的橋梁。
它讀取字節(jié),并使用指定的字符集將其解碼為字符。它的字符集可以由名稱指定,也可以接受平臺的默認(rèn)字符集。
構(gòu)造方法
- InputStreamReader(InputStream in): 創(chuàng)建一個使用默認(rèn)字符集的字符流。
- InputStreamReader(InputStream in, String charsetName): 創(chuàng)建一個指定字符集的字符流。
參數(shù):
InputSrteam in:字節(jié)輸入流,用來讀取文件中保存的字節(jié)
String charsetName:指定的編碼表名稱,不區(qū)分大小寫,可以實(shí)Utf-8,Gbk。。。。不指定默認(rèn)使用UTF-8
使用步驟:
注意事項:
構(gòu)造方法中指定的編碼表民晨光要和文件的編碼相同,否則會發(fā)生亂碼
OutputStreamWriter類
轉(zhuǎn)換流java.io.OutputStreamWriter ,是Writer的子類,是從字符流到字節(jié)流的橋梁。使用指定的字符集將字符編碼為字節(jié)。它的字符集可以由名稱指定,也可以接受平臺的默認(rèn)字符集。
構(gòu)造方法
- OutputStreamWriter(OutputStream in): 創(chuàng)建一個使用默認(rèn)字符集的字符流。
- OutputStreamWriter(OutputStream in, String charsetName): 創(chuàng)建一個指定字符集的字符流。
參數(shù)
OutputStream out:字節(jié)輸出流,用來寫轉(zhuǎn)換之后的字節(jié)到文件中
String charsetName:指定的編碼表名稱,不區(qū)分大小寫,可以是Utf-8,GBK…,不指定默認(rèn)使用Utf-8
使用步驟
指定編碼寫出
public class OutputDemo {public static void main(String[] args) throws IOException {// 定義文件路徑String FileName = "E:\\out.txt";// 創(chuàng)建流對象,默認(rèn)UTF8編碼OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(FileName));// 寫出數(shù)據(jù)osw.write("你好"); // 保存為6個字節(jié)osw.close();// 定義文件路徑String FileName2 = "E:\\out2.txt";// 創(chuàng)建流對象,指定GBK編碼OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream(FileName2),"GBK");// 寫出數(shù)據(jù)osw2.write("你好");// 保存為4個字節(jié)osw2.close();} }練習(xí):轉(zhuǎn)換文件編碼
將GBK編碼的文本文件,轉(zhuǎn)換為UTF-8編碼的文本文件。
案例分析
1.創(chuàng)建InputStreanReader對象,構(gòu)造方法中傳遞字節(jié)輸入流和指定的編碼表名稱GBK
2.創(chuàng)建OutputStreamWrite對象,構(gòu)造方法中傳遞字節(jié)輸出流和指定的編碼表utf-8
3.使用InputSteamReader對象中的方法read讀取文件
4.使用OutputStreamWrite方法write,把讀取的數(shù)據(jù)寫入到文件中
5.釋放資源
案例實(shí)現(xiàn)
public class TransDemo {public static void main(String[] args) { // 1.定義文件路徑String srcFile = "file_gbk.txt";String destFile = "file_utf8.txt";// 2.創(chuàng)建流對象// 2.1 轉(zhuǎn)換輸入流,指定GBK編碼InputStreamReader isr = new InputStreamReader(new FileInputStream(srcFile) , "GBK");// 2.2 轉(zhuǎn)換輸出流,默認(rèn)utf8編碼OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(destFile));// 3.讀寫數(shù)據(jù)// 3.1 定義數(shù)組char[] cbuf = new char[1024];// 3.2 定義長度int len;// 3.3 循環(huán)讀取while ((len = isr.read(cbuf))!=-1) {// 循環(huán)寫出osw.write(cbuf,0,len);}// 4.釋放資源osw.close();isr.close();} }序列化
概述
Java 提供了一種對象序列化的機(jī)制。用一個字節(jié)序列可以表示一個對象,該字節(jié)序列包含該對象的數(shù)據(jù)、對象的類型和對象中存儲的屬性等信息。字節(jié)序列寫出到文件之后,相當(dāng)于文件中持久保存了一個對象的信息。
反之,該字節(jié)序列還可以從文件中讀取回來,重構(gòu)對象,對它進(jìn)行反序列化。對象的數(shù)據(jù)、對象的類型和對象中存儲的數(shù)據(jù)信息,都可以用來在內(nèi)存中創(chuàng)建對象。
把對象以流的方式,寫入到文件中保存,叫寫對象,也可以叫對象的序列化
對象中包含的不僅僅是字符使用字節(jié)流
ObjectOutputStream:對象的序列化writeObject(p)
把文件中保存的對象,以流的方式讀取出來,叫做讀對象,也叫對象的反序列化
讀取的文件保存的都是字節(jié)使用字節(jié)流
ObjectInputStream:對象的反序列化流
readObject()
ObjectOutputStream類
作用:把對象以流的方式寫入到文件中保存
java.io.ObjectOutputStreamextends OutputStream 類,將Java對象的原始數(shù)據(jù)類型寫出到文件,實(shí)現(xiàn)對象的持久存儲。
構(gòu)造方法
- public ObjectOutputStream(OutputStream out): 創(chuàng)建一個指定OutputStream的ObjectOutputStream。
參數(shù):
OutputStream out:字節(jié)輸出流
構(gòu)造舉例,代碼如下:
特有的成員方法:
- public final void writeObject (Object obj) : 將指定的對象寫出。
使用步驟,需要序列化對象實(shí)現(xiàn)類
1.創(chuàng)建ObjectOutputStream對象,構(gòu)造方法中傳遞字節(jié)輸出流
2.使用ObjectOutputStream對象中的方法writeObject,把對象寫入到文件中
3.釋放資源
序列化操作
1.一個對象要想序列化,必須滿足兩個條件:
-
該類必須 實(shí)現(xiàn)java.io.Serializable 接口來啟用序列化功能,Serializable 是一個標(biāo)記接口,不實(shí)現(xiàn)此接口的類將不會使任何狀態(tài)序列化或反序列化,會拋出NotSerializableException 。實(shí)現(xiàn)Serializable接口,會給類添加一個標(biāo)記,當(dāng)序列化和反序列化的時候,就會檢測類上是否有這個標(biāo)記
-
該類的所有屬性必須是可序列化的。如果有一個屬性不需要可序列化的,則該屬性必須注明是瞬態(tài)的,使用transient 關(guān)鍵字修飾。
-
static關(guān)鍵字:靜態(tài)關(guān)鍵字
靜態(tài)優(yōu)先于非靜態(tài)加載到內(nèi)存中(靜態(tài)優(yōu)先于對象進(jìn)入到內(nèi)存中)被static修飾的成員變量不能被序列化
- transient 瞬態(tài)關(guān)鍵字: 被其修飾,不能被序列化
2.寫出對象方法
- public final void writeObject (Object obj) : 將指定的對象寫出。
ObjectInputStream類
ObjectInputStream反序列化流,將之前使用ObjectOutputStream序列化的原始數(shù)據(jù)恢復(fù)為對象。
作用:把文件中保存的對象,以流的方式讀取出來使用
構(gòu)造方法
- public ObjectInputStream(InputStream in): 創(chuàng)建一個指定InputStream的ObjectInputStream。
參數(shù)InputStream in:字節(jié)輸入流
特有成員方法:
- public final Object readObject () : 從ObjectInputStream讀取一個對象。
使用步驟:
1.創(chuàng)建一個ObjectInputStream對象,構(gòu)造方法中傳遞字節(jié)輸入流
2.使用ObjectInputStream對象中的方法readObject讀取保存對象的文件
3.釋放資源
4.使用讀取出來的對象
反序列化操作1
如果能找到一個對象的class文件,我們可以進(jìn)行反序列化操作,調(diào)用ObjectInputStream讀取對象的方法:
- public final Object readObject () : 讀取一個對象。
readObject方法聲明拋出了ClassNotFoundException(class文件找不到異常)當(dāng)不存在對象的class文件時拋出異常
反序列化前提:
對于JVM可以反序列化對象,它必須是能夠找到class文件的類。如果找不到該類的class文件,則拋出一個 ClassNotFoundException 異常。
反序列化操作2
**另外,當(dāng)JVM反序列化對象時,能找到class文件,但是class文件在序列化對象之后發(fā)生了修改,那么反序列化操作也會失敗,拋出一個InvalidClassException異常。**發(fā)生這個異常的原因如下:
- 該類的序列版本號與從流中讀取的類描述符的版本號不匹配
- 該類包含未知數(shù)據(jù)類型
- 該類沒有可訪問的無參數(shù)構(gòu)造方法
Serializable 接口給需要序列化的類,提供了一個序列版本號。serialVersionUID 該版本號的目的在于驗證序列化的對象和對應(yīng)類是否版本匹配。
問題:
每次修改類的定義,都會給class文件生成一個新得序列號
解決方法:
無論是否對類的定義進(jìn)行修改,都不生成新的序列號
可以手動給類添加一個序列號
格式在Serializable 接口規(guī)定:
可序列化類可以通過聲明為serialVersionUID的字段(該字段必須是static)最終final的long星字段,顯示聲明其自己的serialVersionUID
static final long serialVersionUID=42L
public class Employee implements java.io.Serializable {// 加入序列版本號private static final long serialVersionUID = 1L;public String name;public String address;// 添加新的屬性 ,重新編譯, 可以反序列化,該屬性賦為默認(rèn)值.public int eid; public void addressCheck() {System.out.println("Address check : " + name + " -- " + address);} }練習(xí):序列化集合
練習(xí):
當(dāng)我們想在文件中保存多個對象的時候
可以把多個對象存儲到一個集合中
對象進(jìn)行序列化和反序列化
分析:
定義一個存儲Person對象的Array List集合
往ArrayList集合中存儲Person對象
創(chuàng)建一個序列化流ObjectOutputStream
使用ObjectOutputStream對象中的方法writeObject,對集合進(jìn)行序列化
創(chuàng)建一個反序列化Object InputStream對象
使用ObjectInputStream對象中的方法readObject讀取文件中保存的集合
把Object類型的集合轉(zhuǎn)換為ArraysList類型
遍歷ArrayList集合
釋放資源
案例分析
案例實(shí)現(xiàn)
public class SerTest {public static void main(String[] args) throws Exception {// 創(chuàng)建 學(xué)生對象Student student = new Student("老王", "laow");Student student2 = new Student("老張", "laoz");Student student3 = new Student("老李", "laol");ArrayList<Student> arrayList = new ArrayList<>();arrayList.add(student);arrayList.add(student2);arrayList.add(student3);// 序列化操作// serializ(arrayList);// 反序列化 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("list.txt"));// 讀取對象,強(qiáng)轉(zhuǎn)為ArrayList類型ArrayList<Student> list = (ArrayList<Student>)ois.readObject();for (int i = 0; i < list.size(); i++ ){Student s = list.get(i);System.out.println(s.getName()+"--"+ s.getPwd());}}private static void serializ(ArrayList<Student> arrayList) throws Exception {// 創(chuàng)建 序列化流 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("list.txt"));// 寫出對象oos.writeObject(arrayList);// 釋放資源oos.close();} }打印流
概述
平時我們在控制臺打印輸出,是調(diào)用print方法和println方法完成的,這兩個方法都來自于java.io.PrintStream類,該類能夠方便地打印各種數(shù)據(jù)類型的值,是一種便捷的輸出方式。
PrintStream類extends OutputStream
為其他輸出流添加了功能,是他們能夠方便的打印各種數(shù)據(jù)值表示形式
特點(diǎn):
構(gòu)造方法
-
public PrintStream(String fileName): 使用指定的文件名創(chuàng)建一個新的打印流。輸出目的地是一個文件路徑
-
public PrintStream(File file): 使用指定的文件創(chuàng)建一個新的打印流。輸出目的地是一個文件
-
public PrintStream(Output Stream): 使用指定的輸出流創(chuàng)建一個新的打印流。輸出目的地是一個字節(jié)輸出流
構(gòu)造舉例,代碼如下:
PrintStream ps = new PrintStream("ps.txt");繼承自父類的成員方法
- public void close() :關(guān)閉此輸出流并釋放與此流相關(guān)聯(lián)的任何系統(tǒng)資源。
- public void flush() :刷新此輸出流并強(qiáng)制任何緩沖的輸出字節(jié)被寫出。
- public void write(byte[] b):將 b.length字節(jié)從指定的字節(jié)數(shù)組寫入此輸出流。
- public void write(byte[] b, int off, int len) :從指定的字節(jié)數(shù)組寫入 len字節(jié),從偏移量 off開始輸出到此輸出流。
- public abstract void write(int b) :將指定的字節(jié)輸出流。
注意事項
如果使用繼承自父類的write方法寫數(shù)據(jù),那么查看數(shù)據(jù)的時候會查詢編碼表
如果使用自己特有的print/println方法寫數(shù)據(jù),寫的數(shù)據(jù)會原樣輸出
使用步驟
改變打印流向
System.out就是PrintStream類型的,只不過它的流向是系統(tǒng)規(guī)定的,打印在控制臺上。
可以改變輸出語句的目的地(打印流的流向)
輸出語句,默認(rèn)在控制臺輸出
使用System.setOut方法改變輸出語句的目的地改為參數(shù)傳遞的打印流的目的地
static void setOut(PrintStream out )
重新分配“標(biāo)準(zhǔn)”輸出流
總結(jié)
以上是生活随笔為你收集整理的Java笔记整理六(File类,递归,字节流IO,字符流IO,流中的异常处理,属性集Properties,缓冲流,转换流,序列化,打印流)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JAVA SSL数字证书
- 下一篇: Java 支付宝手机网站支付下单 支付回