Java-IO流詳解
-
- 一、IO流相關概念介紹
- 二、位元組輸出流OutputStream
- 三、位元組輸入流InputStream
- 四、Reader字元輸入流
- 五、 Writer字元輸出流
- 五、IO異常的處理
- 六、Properties集合
- 七、緩沖流概述
- 八、位元組緩沖輸出流BufferedOutputStream
- 九、位元組緩沖輸入流BufferedInputStream
- 十、字元緩沖輸出流BufferedWriter
- 十一、字元緩沖輸入流BufferedReader
- 十二、轉換流OutputStreamWriter
- 十三、轉換流InputStreamReader
- 十三、序列化
- 十四、反序列化
- 十五、列印流
一、IO流相關概念介紹
IO流:輸入與輸出流,其實輸入輸出可以用記憶體作為參照,輸入指的是把硬碟中的資料讀取到記憶體中使用,輸出指的是把記憶體的資料寫入到硬碟儲存。
IO流分類:
位元組流:位元組輸入流InputStream 位元組輸出流OutputStream
字元流: 字元輸入Reader 字元輸出流Writer
注意:在計算機中,一切檔案資料在存儲時都是以二進制數字形式存儲的,傳輸時也如此,是以位元組流可以傳輸任意檔案資料。在操作時,無論使用什麼流對象,底層傳輸的都是二進制資料。
二、位元組輸出流OutputStream
java.io.OutputStream,是一個抽象類,此抽象類是表示位元組輸出流的所有類的父類。
定義的共性方法:
public void close():關閉此輸出流并釋放與此流相關聯的任何系統資源。
public void flush():重新整理此輸出流并強制任何緩沖的輸出位元組流。
public void write(byte[] b):将b.lengh位元組從指定的位元組數組寫入輸出流
一次性寫入多個位元組,如果寫的第一個位元組是正數(0-127),顯示的時候會 查詢ASCII表,如果寫的第一個位元組是負數,那麼第一個位元組會和第二個位元組,兩個位元組組成一個中文顯示,查詢系統預設編碼表(簡體中文是GBK)。
public void write(byte[] b,int off,int len):從指定的位元組數組寫入len位元組,從偏移量off(開始的索引)開始輸出到此輸出流。
public void write(int b):将指定的位元組寫入輸出流。
注意:OutputStream是一個抽象類,想要使用方法,需要使用子類對象,常用的子類FileOutputStream(檔案位元組輸出流)。
構造方法:
FileOutputStream(String name):建立向指定名稱的檔案中寫入資料的輸出檔案流。
FileOutputStream(File file):建立向指定file對象中寫入資料的輸出檔案流。
構造方法的作用:
1.建立一個FileOutputStream對象。
2.會根據構造方法中傳遞的檔案/檔案路徑,建立一個空檔案。
3.會把建立好的FileOutputStream指向建立好的檔案。
寫入資料的原理:
java程式->JVM->OS(作業系統)->OS調用寫資料的方法->把資料寫入到檔案中。
位元組輸出流的使用步驟:
(下面幾個步驟都會抛出異常,可以一次性抛出異常IOException)
1.建立一個FileOutputStream對象,構造方法中傳遞檔案寫入的路徑或對象。
2.調用對象中得write方法。
3.釋放資源(流的使用會占用一定的記憶體,使用完畢要把記憶體清空,提高程式的效率)。
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
public class IoDemo01 {
public static void main(String[] args) throws IOException {
// 1.建立一個FileOutputStream對象,構造方法中傳遞檔案寫入的路徑或對象(會抛出異常)
FileOutputStream f = new FileOutputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");//絕對路徑和相對路徑都可以
// 2.調用對象中得write方法
f.write(65);//寫入的資料為A
// public void write(byte[] b):将b.lengh位元組從指定的位元組數組寫入輸出流
//一次性寫入多個位元組,如果寫的第一個位元組是正數(0-127),顯示的時候會查詢ASCII表,如果寫的第一個位元組是負數
//那麼第一個位元組會和第二個位元組,兩個位元組組成一個中文顯示,查詢系統預設編碼表(簡體中文是GBK)
//第一個位元組是正數
byte[] b1 ={66,67,65,66};//BCAB
f.write(b1);
//第一個位元組是負數
byte[] b2 ={-66,65,67,69};
f.write(b2);//続CE
// public void write(byte[] b,int off,int len):從指定的位元組數組寫入len位元組,從偏移量off開始輸出到此輸出流
f.write(b1, 0, 1);//B
/*
寫入字元串的方法:可以使用String類中的getBytes()方法把字元串轉換為位元組數組
*/
String s ="字元串";
byte[] b3 = s.getBytes();
//會将字元串轉成對應的位元組數組
System.out.println(Arrays.toString(b3));//[-41, -42, -73, -5, -76, -82]
f.write(b3);//字元串
// 3.釋放資源(流的使用會占用一定的記憶體,使用完畢要把記憶體清空,提高程式的效率)
f.close();
}
}
追加寫資料:使用兩個參數的構造方法:
FileOutputStream(File file, boolean append) 建立檔案輸出流以寫入由指定的 File對象表示的檔案。
append - 如果 true ,則位元組将被寫入檔案的末尾而不是開頭。
false-建立新檔案,覆寫原來的檔案。
FileOutputStream(String name, boolean append) 建立檔案輸出流以指定的名稱寫入檔案。
append - 如果 true ,則位元組将被寫入檔案的末尾而不是開頭。
false-建立新檔案,覆寫原來的檔案。
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class IoDemo02 {
public static void main(String[] args) throws IOException {
// append - 如果 true ,則位元組将被寫入檔案的末尾而不是開頭
//false-建立新檔案,覆寫原來的檔案
FileOutputStream f = new FileOutputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt",true);
//2.調用對象中得write方法
f.write("hello".getBytes());
//3.釋放資源
f.close();
}
}
三、位元組輸入流InputStream
java.io.InputStream抽象類,此抽象類表示所有位元組輸入流的父類。
定義的共性方法:
int read():從輸入流中讀取資料的下一個位元組,讀取到檔案末尾傳回-1。
int read(byte[] b):從輸入流中讀取一定數量的位元組,并将其存入緩沖區數組b中。
void close():關閉此輸入流并釋放有關的所有系統資源。
注意:InputStream也是一個抽象類,需要使用子類來進行方法的使用,常用子類為FileInputStream。
構造方法:
FileInputStream(String name)通過打開與實際檔案的連接配接來建立一個 FileInputStream ,該檔案由檔案系統中的路徑名 name命名。
FileInputStream(File file)通過打開與實際檔案的連接配接建立一個 FileInputStream ,該檔案由檔案系統中的 File對象 file命名。
構造方法的作用:
1.建立一個 FileInputStream對象,構造方法中指定讀取的路徑或檔案。
2.會把 FileInputStream對象指向要讀取的檔案。
讀取資料原理:
java程式->JVM->OS->OS讀取方法->讀取檔案
位元組輸入流使用步驟:
1.建立建立一個 FileInputStream對象,構造方法中指定讀取的路徑或檔案。
2.調用對象中read方法,讀取檔案。
3.釋放資源。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
public class IoDemo03 {
public static void main(String[] args) throws IOException {
// 1.建立建立一個 FileInputStream對象,構造方法中指定讀取的路徑或檔案
FileInputStream f = new FileInputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
//2.調用對象中read方法,讀取檔案,要多次讀取可以使用循環
//int read():從輸入流中讀取資料的下一個位元組,讀取到檔案末尾傳回-1
// int i1=f.read();
// System.out.println(i1);//65
//
// int i2=f.read();
// System.out.println(i2);//66
//
// int i3=f.read();
// System.out.println(i3);//-1 ,讀取到檔案末尾傳回-1
// int read(byte[] b):從輸入流中讀取一定數量的位元組,并将其存入緩沖區數組b中
byte[] b = new byte[3];
int i4 = f.read(b);
System.out.println(i4);//2
System.out.println(Arrays.toString(b));//[65, 66, 0]
//3.釋放資源
f.close();
}
}
四、Reader字元輸入流
java.io.Reader抽象類,是所有字元輸入流的頂層父類。
位元組流讀取中文時可能不會顯示完整字元,因為在UTF-8格式下一個中文字元占用3個位元組,GBK格式下一個中文字元占用2個位元組,是以Java中有了對應的字元輸入輸出流。
Reader定義的一些共性方法:
int read():讀取單個字元并傳回
int read(char[] ch):一次讀取多個字元,将字元存入數組
void close():關閉流并釋放資源
注意:Reader是一個抽象類,需要使用子類,重點介紹FileReader
FileReader:檔案字元輸入流,用于将字元從硬碟檔案中的資料以字元的形式讀取到記憶體中。
構造方法:
FlieReader(String filename):建立一個新的 FileReader, 給定要讀取的檔案的名稱。
FilleReader(File file):建立一個新的 FileReader ,給出 File讀取。
使用步驟:
1.建立FlieReader對象,并在構造方法中指定資料源。
2.使用read方法進行字元讀取。
3.釋放資源。
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
public class IoDemo04 {
public static void main(String[] args) throws IOException {
// FileInputStream f = new FileInputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
// while(f.read()!=-1){
// System.out.println((char)f.read());//産生亂碼
// }
// f.close();
// 1.建立FlieReader對象,并在構造方法中指定資料源
FileReader f = new FileReader("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
//2.使用read方法進行字元讀取
// int read():讀取單個字元并傳回
int i1 = f.read();
System.out.println((char)i1);//進行類型轉換
//int read(char[] ch):一次讀取多個字元,将字元存入數組
char[] ch = new char[100];//存儲讀取到的資料
int i2 = 0;//記錄讀取的有效資料
while((f.read(ch)!=-1)){//和位元組流一樣,檔案末尾讀取-1
/*
輸出可以使用String類的構造方法:
String(char[] value):把字元數組轉化為字元串
String(char[] value,int offset,int len):把字元數組從索引offset開始,len長轉換為字元串
*/
System.out.print(new String(ch,0,5));
}
//3.釋放資源
f.close();
}
}
五、 Writer字元輸出流
java.io.Writer抽象類,是所有字元輸出流的最頂層父類。
共性的成員方法;
void write(int c) 寫入單個字元。
void write(char[] ch)寫入字元數組。
void write(String str)寫一個字元串。
void write(String str, int off, int len)寫一個字元串的一部分。
abstract void write(char[] ch, int off, int len)寫一個字元數組的一部分。
void flush()重新整理該流的緩沖。
void close():關閉此流,但要先重新整理。
注意:Writer是一個抽象類,想要使用必須使用其子類對象,重點介紹FileWriter。
FlieWriter:檔案字元輸出流,把記憶體中的資料寫入檔案。
構造方法:
FileWriter(String fileName)構造一個給定檔案名的FileWriter對象。
FileWriter(File file)給一個File對象構造一個FileWriter對象。
使用步驟:
1.建立一個FileWriter對象,在其構造方法中寫入資料存儲路徑。
2.使用FileWriter中的方法write,把資料寫入到記憶體緩沖區(字元轉換為位元組的過程)。
3.使用flush方法,把記憶體緩沖區中的資料,重新整理到檔案中。
4.釋放資源。
注意:
flush方法:重新整理緩沖區,流對象可以繼續使用。
close方法:先重新整理緩沖區,再通知系統釋放資源,流對象不可再使用。
import java.io.FileWriter;
import java.io.IOException;
public class IoDemo05 {
public static void main(String[] args) throws IOException {
// 1.建立一個FileWriter對象,在其構造方法中寫入資料存儲路徑
FileWriter f = new FileWriter("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
// 2.使用FileWriter中的方法write,把資料寫入到記憶體緩沖區(字元轉換為位元組的過程)
//void write(int c) 寫入單個字元
f.write(67);
//3.使用flush方法,把記憶體緩沖區中的資料,重新整理到檔案中
f.flush();//C
//釋放資源
f.close();//其實釋放資源時會先執行flush方法
}
}
FileWriter續寫及追擊資料的方法:
FileWriter(File file, boolean append)給一個File對象構造一個FileWriter對象。
append:布爾值,如果為true,不會建立新的檔案覆寫源檔案,如果為false,建立新的檔案覆寫源檔案。
FileWriter(String fileName, boolean append)構造一個FileWriter對象,給出一個帶有布爾值的檔案名,表示是否附加寫入的資料。
append:布爾值,如果為true,不會建立新的檔案覆寫源檔案,如果為false,建立新的檔案覆寫源檔案。
import java.io.FileWriter;
import java.io.IOException;
public class IoDemo06 {
public static void main(String[] args) throws IOException {
FileWriter f = new FileWriter("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt",true);
f.write("呵呵");
//f.flush();
f.close();
}
}
五、IO異常的處理
IO異常的處理,使用try-catch-finally來進行處理。
在JDK1.7之前IO異常的處理
格式:
try
{可能出現異常的代碼}
catch(異常對象 變量名){
異常的處理邏輯
}finally{
一定會執行的代碼,也就是資源釋放
}
在JDK1.7後增加了新特性,在try後面加上一個小括号,裡面可以定義流對象,try中代碼執行完畢,會自動把資源進行釋放,不用再寫finally。
格式:
try(定義流對象){//可以定義多個流對象,之間用逗号隔開
可能産生異常的代碼
}catch(異常類變量 變量名){
異常的處理邏輯
}
在JDK1.9以後又增加了新特性,try的前面可以定義流對象,在try的後面括号可以直接引入流對象的名稱(變量名)在try代碼執行完畢之後流對象也可以釋放掉,不用寫finally。
A a new = A();
B b new = B();
try(a,b)
{
可能出現異常的代碼
}
catch(異常對象 變量名){
異常的處理邏輯
}
import java.io.FileWriter;
import java.io.IOException;
public class IoDemo07 {
public static void main(String[] args) {
FileWriter f = null;
try{
//可能出現異常的代碼
f = new FileWriter("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
f.write("呵呵");
}catch(IOException e){
//異常的處理邏輯
System.out.println(e);
}finally{
try {
f.close();//因為局部變量的作用域隻在最近的大括号才能生效,是以需要提高定義範圍
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//JDK1.7後增加了新特性
try(FileWriter f1 = new FileWriter("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
FileWriter f2 = new FileWriter("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
){
f1.write("哈哈");
f2.write("哈哈");
}catch(IOException e){
System.out.println(e);
}
}
}
六、Properties集合
java.util.Properties extends Hashtable<K,V> implements Map<K,V>, Properties(雙列集合)是唯一一個與IO流相結合的集合,表示一組持久的屬性。 Properties可以儲存到流中或從流中加載。屬性清單中的每個鍵及其對應的值都是一個字元串(key和value預設都是字元串)。
Properties中特有方法:
将集合中的資料(臨時資料),存儲到硬碟中(持久化資料)。
void store(OutputStream out, String comments) 将此屬性清單(鍵和元素對)寫入此 Properties表中,以适合于使用load(InputStream)方法加載到 Properties表中的格式輸出流。
OutputStream out:位元組輸出流,不能寫入中文
comments:注釋,用來解釋說明文檔,不能使用中文,預設為Unicode編碼一般使用空字元串""。
void store(Writer writer, String comments)将此屬性清單(鍵和元素對)寫入此 Properties表中,以适合使用 load(Reader)方法的格式輸出到輸出字元流。
Writer writer:位元組輸入流,能寫入中文。
comments:注釋,用來解釋說明文檔,不能使用中文,預設為Unicode編碼一般使用空字元串""。
将硬碟中儲存的檔案(鍵值對組成的)讀取到集合中進行使用:
void load(InputStream inStream)從輸入位元組流讀取屬性清單(鍵和元素對)。
InputStream inStream:位元組輸入流,不能讀取中文字元的鍵值對。
void load(Reader reader)以簡單的線性格式從輸入字元流讀取屬性清單(關鍵字和元素對)。
Reader reader:字元輸入流,能讀取含有中文的鍵值對
其它常用方法:
Object setProperty(String key, String value)相當于 Hashtable中方法 put。
String getProperty(String key)通過key找到對應的value值,相當于Map中的get方法。
Set stringPropertyNames()傳回此屬性清單中的一組鍵,其中鍵及其對應的值為字元串,相當于Map集合中keySet方法。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
public class IoDemo08 {
public static void main(String[] args) throws IOException {
//不需要指定泛型,預設都是字元串
Properties pr = new Properties();
//Object setProperty(String key, String value)相當于 Hashtable中方法 put
pr.setProperty("唐三藏", "唐僧");
pr.setProperty("孫行者", "孫悟空");
pr.setProperty("天蓬元帥", "豬八戒");
//key和value都是字元串,不能是其它類型
//pr.setProperty(1, 1);
//String getProperty(String key)通過key找到對應的value值,相當于Map中的get方法
String value = pr.getProperty("孫行者");
System.out.println(value);//輸出結果:孫悟空
//Set<String> stringPropertyNames()傳回此屬性清單中的一組鍵,其中鍵及其對應的值為字元串,相當于Map集合中keySet方法
Set<String> names = pr.stringPropertyNames();
for(String key:names){
System.out.print(key+"="+pr.getProperty(key)+" ");//輸出結果:天蓬元帥=豬八戒 唐三藏=唐僧 孫行者=孫悟空
}
/*
void store(OutputStream out, String comments)
void store(Writer writer, String comments)
使用步驟:
1.建立Properties集合,并完成添加資料
2.建立一個OutputStream流對象/Writer流對象,在構造方法中指定輸出路徑
3.調用Properties中store方法,進行輸出
4.釋放資源
*/
// 1.建立Properties集合,并完成添加資料
Properties pr1 = new Properties();
//Object setProperty(String key, String value)相當于 Hashtable中方法 put
pr1.setProperty("唐三藏", "唐僧");
pr1.setProperty("孫行者", "孫悟空");
pr1.setProperty("天蓬元帥", "豬八戒");
// 2.建立一個OutputStream流對象/Writer流對象,在構造方法中指定輸出路徑
//OutputStream流對象
FileOutputStream out = new FileOutputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
//Writer流對象
FileWriter writer = new FileWriter("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
//3.調用Properties中store方法,進行輸出
// OutputStream out:位元組輸出流,不能寫入中文,會産生亂碼
//pr1.store(out,"storage");
/* #storage
#Mon Feb 08 10:34:31 CST 2021
\u5929\u84EC\u5143\u5E05=\u732A\u516B\u6212
\u5510\u4E09\u85CF=\u5510\u50E7
\u5B59\u884C\u8005=\u5B59\u609F\u7A7A*/
//Writer writer:位元組輸入流,能寫入中文
pr1.store(writer, "storage");
/* #storage
#Mon Feb 08 10:31:33 CST 2021 //時間是預設加的
天蓬元帥=豬八戒
唐三藏=唐僧
孫行者=孫悟空*/
// 4.釋放資源
out.close();
writer.close();
System.out.println();
/*
void load(InputStream inStream)從輸入位元組流讀取屬性清單(鍵和元素對)。
void load(Reader reader)以簡單的線性格式從輸入字元流讀取屬性清單(關鍵字和元素對)
使用步驟:
1.建立一個Properties集合
2.建立InputStream/Reader流對象,在構造方法中指定讀取路徑(可以使用匿名内部類)
3.調用Properties集合中load方法讀取儲存鍵值對的檔案
4.周遊Properties集合
4.釋放資源
注意:
1.存儲鍵值對的檔案,鍵與值連接配接符可以自己定義
2.存儲鍵值對的檔案,鍵與值預設都是字元串,不用再加引号
3.存儲鍵值對的檔案,可以使用#号注釋,注釋的内容不會再被讀取
*/
// 1.建立一個Properties集合
Properties pr3 = new Properties();
//2.建立InputStream/Reader流對象,在構造方法中指定讀取路徑
//InputStream流對象
FileInputStream in = new FileInputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
//Reader流對象
FileReader fr = new FileReader("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
// 3.調用Properties集合中load方法
// pr3.load(in);
pr3.load(fr);
// 4.周遊Properties集合
//InputStream流對象不能讀取中文鍵值對,會産生亂碼
// Set<String> set = pr3.stringPropertyNames();
// for(String key:set){
// System.out.println(key+"="+); /* ??????=孫悟空
// ?ì?????§=唐僧
// ??????=豬八戒*/
// }
//Reader流對象能讀取中文鍵值對
Set<String> set = pr3.stringPropertyNames();
for(String key:set){
System.out.println(key+"="+pr3.getProperty(key));
/*天蓬元帥=豬八戒
唐三藏=唐僧
孫行者=孫悟空*/
}
}
}
七、緩沖流概述
緩沖流:增強基本流的功能,在基本流的基礎上演變而來。
按照資料類型進行分類分為:
位元組緩沖流:BufferedInputStrem BufferedOutputStream
字元緩沖流:BufferedReader BufferedWriter
緩沖流的基本原理:是在建立流對象時會建立一個内置的預設大小的緩沖區數組,通過緩沖區讀寫,減少系統的IO次數,提高讀寫的效率。
八、位元組緩沖輸出流BufferedOutputStream
位元組緩沖輸出流構造方法:
BufferedOutputStream(OutputStream out):建立一個新的緩沖輸出流。
OutputStream out:位元組輸出流對象
BufferedOutputStream(OutputStream out, int size)建立一個新的緩沖輸出流,以便以指定的緩沖區大小将資料寫入指定的底層輸出流。
OutputStream out;位元組輸出流對象
int size:指定位元組緩沖區大小,不指定使用預設值
其它常用成員方法可以使用父類OutputStream中常用方法:
public void close():關閉此輸出流并釋放與此流相關聯的任何系統資源。
public void flush():重新整理此輸出流并強制任何緩沖的輸出位元組流。
public void write(byte[] b):将b.lengh位元組從指定的位元組數組寫入輸出流。一次性寫入多個位元組,如果寫的第一個位元組是正數(0-127),顯示的時候會查詢ASCII表,如果寫的第一個位元組是負數 ,那麼第一個位元組會和第二個位元組,兩個位元組組成一個中文顯示,查詢系統預設編碼表(簡體中文是GBK)。
public void write(byte[] b,int off,int len):從指定的位元組數組寫入len位元組,從偏移量off(開始的索引)開始輸出到此輸出流。
public void write(int b):将指定的位元組寫入輸出流。
使用方法:
1.建立一個FileoutputStream對象,指定資料輸出路徑。
2.建立一個BufferedOutputStream對象,構造方法中傳遞FileoutputStream對象,和指定緩沖區大小,不指定則使用預設值。
3.調用BufferedOutputStream對象的write方法,把資料寫入到緩沖區中。
4.使用BufferedOutputStream對象的flush方法,将緩沖區中的資料重新整理到指定路徑的檔案中去。
5.釋放資源,在調用close方法之前,其實會先調用flush方法,将資料重新整理到檔案中去,是以第4步可選擇性省略。
import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class IoDemo09 {
public static void main(String[] args) throws IOException {
//1.建立一個FileoutputStream對象,指定資料輸出路徑
FileOutputStream out = new FileOutputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
//2.建立一個BufferedOutputStream對象,構造方法中傳遞FileoutputStream對象,和指定緩沖區大小,不指定則使用預設值
BufferedOutputStream bout = new BufferedOutputStream(out,100);
//3.調用BufferedOutputStream對象的write方法,把資料寫入到緩沖區中
//寫入單個資料
// bout.write(97);//a
//寫入一個位元組數組
byte[] bytes = {98,99,97};
bout.write(bytes);//bca
//寫入一個位元組數組的指定長度部分
// bout.write(bytes, 0, 1);//a
// 4.使用BufferedOutputStream對象的flush方法,将緩沖區中的資料重新整理到指定路徑的檔案中去
bout.flush();
//5.釋放資源,在調用close方法之前,其實會先調用flush方法,将資料重新整理到檔案中去,是以第4步可選擇性省略
out.close();
bout.close();
}
}
九、位元組緩沖輸入流BufferedInputStream
構造方法:
BufferedInputStream(InputStream in)建立一個BufferedInputStream并儲存其參數,輸入流 in ,供以後使用。
InputStream in;位元組輸入流對象
BufferedInputStream(InputStream in, int size)建立 BufferedInputStream具有指定緩沖區大小,并儲存其參數,輸入流 in ,供以後使用。
InputStream out;位元組輸入流對象
int size:指定位元組緩沖區大小,不指定使用預設值
常用方法繼承自父類InputStream:
int read():從輸入流中讀取資料的下一個位元組,讀取到檔案末尾傳回-1。
int read(byte[] b):從輸入流中讀取一定數量的位元組,并将其存入緩沖區數組b中。
void close():關閉此輸入流并釋放有關的所有系統資源。
使用步驟:
1.建立一個InputStream流對象,構造方法中指定讀取的路徑或者檔案。
2.建立BufferedInputStream對象,構造方法中傳入InputStream流對象,可以指定大小,也可以不寫,使用預設值。
3.調用BufferedInputSteram的read方法,進行檔案的讀取。
4.釋放資源。
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class IoDemo10 {
public static void main(String[] args) throws IOException {
// 1.建立一個InputStream流對象,構造方法中指定讀取的路徑或者檔案
FileInputStream f = new FileInputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
//2.建立BufferedInputStream對象,構造方法中傳入InputStream流對象,可以指定大小,也可以不寫,使用預設值
BufferedInputStream bf = new BufferedInputStream(f);
//3.調用BufferedInputSteram的read方法,進行檔案的讀取
byte[] bytes = new byte[100];//定義存儲資料
while(f.read(bytes)!=-1){//和InputStream一樣,讀取檔案末尾為-1
System.out.print(new String(bytes,0,3));//bca
}
// 4.釋放資源
bf.close();
}
}
十、字元緩沖輸出流BufferedWriter
構造方法:
BufferedWriter(Writer out)建立使用預設大小的輸出緩沖區的緩沖字元輸出流。
Writer out;字元輸出流對象。
BufferedWriter(Writer out, int size)建立一個新的緩沖字元輸出流,使用給定大小的輸出緩沖區。
Writer out;字元輸出流對象。
int size:指定位元組緩沖區大小,不指定使用預設值。
特有操作方法:
void newLine()寫一行行分隔符,會根據不同的作業系統擷取不同的行分隔符。
其它常用操作方法繼承自父類Writer:
void write(int c) 寫入單個字元
void write(char[] ch)寫入字元數組
void write(String str)寫一個字元串
void write(String str, int off, int len)寫一個字元串的一部分
abstract void write(char[] ch, int off, int len)寫一個字元數組的一部分。
void flush()重新整理該流的緩沖
void close():關閉此流,但要先重新整理
使用步驟:
1.建立一個FileWriter流對象,構造方法中指定資料輸出路徑。
2.建立一個BufferedWriter對象,構造方法中傳遞Writer流對象,根據需要指定緩沖區大小,可以不指定大小,使用預設值。
3.調用BufferedWriter對象中的write方法,進行資料寫入到記憶體緩沖區。
4.使用BufferedWriter中的方法flush,将記憶體緩沖區中的資料重新整理到檔案中。
5.釋放資源。
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class IoDemo11 {
public static void main(String[] args) throws IOException {
//1.建立一個FileWriter流對象,構造方法中指定資料輸出路徑
FileWriter f = new FileWriter("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
// 2.建立一個BufferedWriter對象,構造方法中傳遞Writer流對象,根據需要指定緩沖區大小,可以不指定大小,使用預設值
BufferedWriter bw = new BufferedWriter(f);
// 3.調用BufferedWriter對象中的write方法,進行資料寫入到記憶體緩沖區
// void write(int c) 寫入單個字元
bw.write(99);//c
// void write(char[] ch)寫入字元數組
char[] ch={'a','b','c'};
bw.write(ch);//abc
//void newLine()寫一行行分隔符,會根據不同的作業系統擷取不同的行分隔符
bw.newLine();
//void write(String str)寫一個字元串
bw.write("哈哈");//哈哈
// void write(String str, int off, int len)寫一個字元串的一部分
String str = "hello";
bw.write(str,0,3);//hel
// 4.使用BufferedWriter中的方法flush,将記憶體緩沖區中的資料重新整理到檔案中
bw.flush();
//5.釋放資源
bw.close();
}
}
十一、字元緩沖輸入流BufferedReader
構造方法:
BufferedReader(Reader in)建立使用預設大小的輸入緩沖區的緩沖字元輸入流。
BufferedReader(Reader in, int size)建立使用指定大小的輸入緩沖區的緩沖字元輸入流。
特有操作方法:
String readLine()讀一行文字(讀一行文字。 一行被視為由換行符(’\ n’),回車符(’\ r’)中的任何一個或随後的換行符終止)。
傳回值:包含行的内容的字元串,不包括任何行終止字元,如果已達到流的末尾,則為null。
常用操作其它方法繼承自父類Reader:
int read():讀取單個字元并傳回。
int read(char[] ch):一次讀取多個字元,将字元存入數組。
void close():關閉流并釋放資源。
使用步驟:
1.建立一個FileReader流對象,構造方法中傳遞讀取的檔案路徑。
2.建立BuffedReader對象,構造方法中傳遞FileReader流對象,并可以指定緩沖區大小,也可不指定,使用預設大小。
3.調用BufferedReader中的read/readLine方法,進行文本讀取。
4.釋放資源。
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class IoDemo12 {
public static void main(String[] args) throws IOException {
// 1.建立一個FileReader流對象,構造方法中傳遞讀取的檔案路徑
FileReader f = new FileReader("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
//2.建立BuffedReader對象,構造方法中傳遞FileReader流對象,并可以指定緩沖區大小,也可不指定,使用預設大小
BufferedReader br = new BufferedReader(f);
//3.調用BufferedReader中的read/readLine方法,進行文本讀取
int a = br.read();
String str = br.readLine();
System.out.println((char)a);//輸出結果:c
System.out.println(str);//輸出結果:abc
// 4.釋放資源
br.close();
}
}
十二、轉換流OutputStreamWriter
OutputStreamWriter:是字元流轉換成位元組流的通道,可使用指定的charset将寫入流中的字元編碼成位元組。
如果使用不同的編碼表進行檔案的讀取和寫入,會出現亂碼,如eclipse系統預設為GBK,如果讀取UTF-8檔案就會出錯。Java中提供了轉換流來進行不同編碼表的轉換,為OutputStreamWriter和InputStreamReader。
構造方法:
OutputStreamWriter(OutputStream out)建立一個使用預設字元編碼的OutputStreamWriter。
OutputStream out:位元組流對象。
OutputStreamWriter(OutputStream out, String charsetName)建立一個使用命名字元集的OutputStreamWriter。
OutputStream out:位元組流對象
charsetName:指定字元集名稱,不區分大小寫
其他常用方法繼承自父類Writer:
void write(int c) 寫入單個字元。
void write(char[] ch)寫入字元數組。
void write(String str)寫一個字元串。
void write(String str, int off, int len)寫一個字元串的一部分。
abstract void write(char[] ch, int off, int len)寫一個字元數組的一部分。
void flush()重新整理該流的緩沖。
void close():關閉此流,但要先重新整理。
使用步驟:
1.建立一個FileOutputStream對象,構造方法中指定輸出資料的檔案或路徑。
2.建立 OutputStreamWriter,構造方法中傳遞為OutputStream對象和指定編碼表名稱。
3.使用 OutputStreamWriter對象中的write方法,把字元轉換為為位元組存出到緩沖區中。
4.使用 OutputStreamWriter中flush方法,将資料重新整理到檔案中
5.釋放資源。
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
public class IoDemo13 {
public static void main(String[] args) throws IOException {
//1.建立一個OutputStream對象,構造方法中指定輸出資料的檔案或路徑
FileOutputStream out = new FileOutputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
// 2.建立 OutputStreamWriter,構造方法中傳遞為OutputStream對象和指定編碼表名稱,不寫預設GBK
OutputStreamWriter outwriter1 = new OutputStreamWriter(out,"GBK");
OutputStreamWriter outwriter2 = new OutputStreamWriter(out,"utf-8");
//3.使用 OutputStreamWriter對象中的write方法,把字元轉換為為位元組存出到緩沖區中
outwriter1.write("你好");//你好
outwriter2.write("你好");//浣犲ソ utf-8出現亂碼
//4.使用 OutputStreamWriter中flush方法,将資料重新整理到檔案中
outwriter1.flush();
outwriter2.flush();
// 5.釋放資源
outwriter1.close();
outwriter2.close();
}
}
十三、轉換流InputStreamReader
InputStreamReader:是從位元組流到字元流的橋:它讀取位元組,并使用指定的charset将其解碼為字元 。它使用的字元集可以由名稱指定,也可以被明确指定,或者可以接受平台的預設字元集。
構造方法:
InputStreamReader(InputStream in)建立一個使用預設字元集的InputStreamReader。
InputStream in:位元組輸入流
InputStreamReader(InputStream in, String charsetName)建立一個使用命名字元集的InputStreamReader。
InputStream in:位元組輸入流
String charsetName:指定字元集,不區分大小寫
其他常用方法繼承自父類Reader:
int read():讀取單個字元并傳回。
int read(char[] ch):一次讀取多個字元,将字元存入數組。
void close():關閉流并釋放資源。
使用步驟:
1.建立一個FileInputStream流對象,構造方法中指定讀取檔案或者檔案路徑。
2.建立InputStreamReader,構造方法中傳遞FileInputStream流對象,并指定字元集,不指定則使用預設字元集。
3.調用InputStreamReader中read方法,進行檔案讀取。
4.釋放資源。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
public class IoDemo14 {
public static void main(String[] args) throws IOException {
// 1.建立一個FileInputStream流對象,構造方法中指定讀取檔案或者檔案路徑
FileInputStream f = new FileInputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
//2.建立InputStreamReader,構造方法中傳遞FileInputStream流對象,并指定字元集,不指定則使用預設字元集
InputStreamReader i1 = new InputStreamReader(f,"GBK");
InputStreamReader i2 = new InputStreamReader(f,"utf-8");
// 3.調用InputStreamReader中read方法,進行檔案讀取,檔案内容為”你好“
int len = 0;//記錄有效資料個數
// while((len=i1.read())!=-1){//檔案末尾為-1
// System.out.print((char)len);//輸出結果:你好
// }
while((len=i2.read())!=-1){
System.out.print((char)len);//輸出結果:???
}
//4.釋放資源
//i1.close();
i2.close();
}
}
十三、序列化
序列化和反序列化:
Java提供了一種對象序列化機制,用一個位元組序列可以表示一個對象,該位元組序清單示該對象的資料、對象的類型和對象中存儲屬性等該位元組序列還可以從檔案中讀取回來,重構對象,對其進行反序列化。
位元組----ObjectOutputStream(序列化-對象轉換為位元組)—>對象
位元組<----ObjectInputStream(反序列化-位元組重構對象)—>對象
序列化:把對象以流的方式,寫入到檔案中儲存。
反序列化:把檔案以流的形式讀取出來。
ObjectOutputStream:對象的序列化流,把對象以流的方式寫入到檔案中儲存。
ObjectOutputStream(OutputStream out)建立一個寫入指定的OutputStream的ObjectOutputStream
特有成員方法:
void writeObject(Object obj)将指定的對象寫入ObjectOutputStream
注意:
序列化與反序列化時候,會抛出NotSerializableException(沒有序列化異常),可以通過将類在定義時實作java.io.Serializable接口
以啟用序列化和反序列化功能,未實作此接口的類将無法進行序列化及反序列化 ,Serializable接口為标記性接口,其中沒有任何抽象方法,隻是在進行序列化和反序列化時檢測類上是否有這個标記,有就可以進行序列化及反序列化,沒有則不可進行序列化及反序列化抛出NotSerializableException(沒有序列化異常)。
使用步驟:
1.建立一個類,實作Serializable接口,并将其執行個體化
2.建立一個FileOutputStream對象,構造方法中指定輸出檔案或路徑。
3.建立ObjectOutputStream對象,構造方法中傳遞OutputStream對象。
4.調用writeObject方法,将對象傳入。
5.釋放資源。
序列化前提:
1.類必須實作Serializable接口,不實作此接口的類将不會使任何狀态序列化或反序列化。
2.該類所有屬性必須使可序列化的,如果有一個屬性不需要可序列化,則該屬性必須标明使注明是瞬态的,即用transient關鍵字修飾。
static關鍵字:靜态關鍵字
靜态關鍵字優先于非靜态關鍵字加載到記憶體中,被static關鍵字修飾的成員變量是不能被序列化的,序列化的都是對象。
transient關鍵字:瞬态關鍵字
被transient關鍵字修飾的成員變量不能被序列化。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class IoDemo15 {
public static void main(String[] args) throws IOException {
//序列化
//1.建立一個自定義對象,并将其執行個體化
Student p = new Student("張三", 19);
//2.建立一個OutputStream對象,構造方法中指定輸出檔案或路徑
FileOutputStream f = new FileOutputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
// 3.建立ObjectOutputStream對象,構造方法中傳遞OutputStream對象
ObjectOutputStream oo = new ObjectOutputStream(f);
//4.調用writeObject方法,将對象傳入
oo.writeObject(p);//進行序列化後結果 sr
// io.Student/[掆?? I ageL stuNamet Ljava/lang/String;xp t 寮犱笁
//5.釋放資源
oo.close();
}
}
class Student implements Serializable{
// 強烈建議所有可序列化的類都明确聲明serialVersionUID值,因為預設的serialVersionUID計算對類詳細資訊非常敏感
static final long serialVersionUID = 666L;
private String stuName;
private /*transient*/ int age;
public Student(String stuName, int age) {
super();
this.stuName = stuName;
this.age = age;
}
public Student() {
super();
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [stuName=" + stuName + ", age=" + age + "]";
}
}
十四、反序列化
ObjectInputStream:對象的反序列化流,把檔案中儲存的對象,以流的方式進行讀取。
構造方法;
ObjectInputStream(InputStream in)建立從指定的InputStream讀取的ObjectInputStream。
特有的成員方法:
Object readObject()從ObjectInputStream讀取一個對象聲明抛出了ClassNotFoundException(class檔案找不到異常),當不存在對象的class檔案時抛出此異常。
使用步驟:
1.建立一個FileInputStream對象,構造方法中傳遞讀取的檔案路徑或檔案
2.建立ObjectInputStream,構造方法中傳遞FileInputStream對象。
3.調用ObjectInputStream中readObject()方法,讀取儲存對象的檔案。
4.釋放資源。
5.列印讀出的對象。
反序列化的前提:
1.所要存儲的的類對象,類必須實作Serializable接口。
2.必須存在類對應的class檔案 。
注意:
當JVM反序列化對象時,能找到class檔案,但是class檔案在序列化對象時發生了修改,那麼反序列化操作也會失敗。抛出InvalidClassException。
發生異常的原因:
1.該類的序列版本号與從流中讀取的類描述符的版本号不比對。
2.該類包含未知資料類型。
3.該類沒有可通路的無參構造方法。
Serializable接口給需要序列化的類,提供了一個版本序列号,serialVersion該版本号的目的在于驗證序列化的對象和對應列是否和對應類比對 。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
public class IoDemo16 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 反序列化
// 1.建立一個FileInputStream對象,構造方法中傳遞讀取的檔案路徑或檔案
FileInputStream fi = new FileInputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
// 2.建立ObjectInputStream,構造方法中傳遞FileInputStream對象
ObjectInputStream oi = new ObjectInputStream(fi);
// 3.調用ObjectInputStream中readObject()方法,讀取儲存對象的檔案
Object obj = oi.readObject();
// 4.釋放資源
oi.close();
// 5.列印讀出的對象
System.out.println(obj);// 輸出結果:Student [stuName=張三, age=19]
//transeint關鍵字修飾後輸出結果;Student [stuName=張三, age=0]
//将age的修飾符改為public後報錯: serialVersionUID = -8505643103320664334, local class serialVersionUID = 2790456493892586949
}
}
十五、列印流
列印流:
java.io.PrintStream:列印流,為另一個輸出流添加了功能,即能夠友善地列印各種資料值的表示。
PrintStream流特點:
1.隻負責輸出,不進行輸入
2.與其他輸出流不同, PrintStream從不抛出IOException相反,異常情況隻是設定一個可以通過checkError方法測試的内部标志。
特有方法:
void print(任意類型的資料)
void println(任意類型資料并換行)
構造方法:
PrintStream(File file)使用指定的檔案建立一個新的列印流,而不需要自動換行(輸出到一個檔案)
PrintStream(OutputStream out)建立一個新的列印流(輸出到一個流)
PrintStream(String fileName)使用指定的檔案名建立新的列印流,無需自動換行(輸出到一個檔案路徑)
PrintStream繼承了OutputStream,是以可以使用父類成員方法:
注意:
如果使用父類成員方法write寫資料,則檢視資料時會查詢編碼表
如果使用自身特有方法print/println,則寫資料時原樣輸出
使用步驟:
1.建立一個PrintStream對象,構造方法中添加資料輸出路徑(會抛出FileNotFoundException)
2.調用父類write方法/自身特有方法,寫入資料
3.釋放資源
可以改變輸出語句的目的地,輸出語句,預設在控制台列印,使用System.setOut方法改變輸出語句的目的地改為參數傳遞的列印流的目的地.
static void setOut(PrintStream out)重新配置設定“标準”輸出流重新配置設定“标準”輸出流。
import java.io.FileNotFoundException;
import java.io.PrintStream;
public class IoDemo18 {
public static void main(String[] args) throws FileNotFoundException {
//1.建立一個PrintStream對象,構造方法中添加資料輸出路徑
PrintStream ps = new PrintStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
// 2.調用父類write方法/自身特有方法,寫入資料
//調用父類write方法
ps.write(101);//e
//自身特有方法
ps.print(101);//101
//3.釋放資源
ps.close();
//static void setOut(PrintStream out)
System.out.println("呵呵");//控制台輸出
PrintStream p = new PrintStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
System.setOut(p);
System.out.println("呵呵在1.txt中輸出");//檔案中輸出
p.close();
}
}