day05
IO流
1 流的作用:
流是對各類檔案的操作,而且是從頭到尾進行讀和寫的 (按順序) 不想RandomAccessFile 一樣可以随意
2 流的分類
按照方向:輸入輸出流
* a: 參照物
*到底是輸入還是輸出,都是以Java程式為參照
*b: Output
*把記憶體中的資料存儲到持久化裝置上這個動作稱為輸出(寫)Output操作
*程式到檔案稱為輸出
*c: Input
*把持久裝置上的資料讀取到記憶體中的這個動作稱為輸入(讀)Input操作
*檔案到程式稱為輸入
*d: IO操作
*把上面的這種輸入和輸出動作稱為IO操作
按照資料機關分:字元流位元組流
位元組流 : 位元組流可以操作任何資料,因為在計算機中任何資料都是以位元組的形式存儲的
字元流 : 字元流隻能操作純字元資料,比較友善。
功能不同:節點流和處理流
節點流(不管是字元節點流還是位元組節點流)可以從特定的資料源上讀取資料 處理流不能單獨使用在資料源上可以套用在節點流或者處理流上面(能用的流說明源代碼已經實作了)
3所有的流類型位于IO包下的四個抽象類
位元組流 | 字元流 | |
輸入流 | InputStream | Reader |
輸出流 | OutputStream | Writer |
5 四大抽象類中的方法
1)inputStream
基本方法
intread(); 讀取一個位元組并且放在int 的低八位以整數的形式傳回 0-255 -1 讀到頭
intread(byte[] buffer); 傳回實際讀取的位元組數如果讀前已經到末尾就傳回 -1 讀到字元數組中
intread(byte[] buffer,int offset ,int length)throws IOException; 讀數組中的開始位置和長度
voidclose() 關閉流
longskip();跳過n個位元組不讀傳回實際跳過的位元組數
2)outputStream
void write(int b) 寫一個位元組并且放在int 的低8位
void write(byte [] b)
void write(byte [] b int offset ,int length) 讀數組中的開始位置和長度
void close() 關閉流
void flush();
3)Reader
int read() 讀取一個字元并且以整數的形式傳回作為整數讀取的字元,範圍在0 到 65535 之間)傳回-1 說明到末尾了放在低16位
int read(char[] buf) 讀到字元數組中傳回實際讀到的字元數
intread(char[] buffer,int offset ,int length)throws IOException; 讀數組中的開始位置和長度
void close() 關閉流
longskip();跳過n個位元組不讀傳回實際跳過的位元組數
4)Writer
void writer (int c) 向輸出流中寫入一個字元資料該位元組資料位參數的低16 位
void write(char [] b) 從字元類型的數組中的資料寫入輸出流
void write(char [] b int offset ,int length) 寫數組中的開始位置和長度到流中
void close() 關閉流
void flush();将輸出流中緩沖的資料全部寫出到目的地
5)flush方法和close方法差別
*a: flush()方法
* 用來重新整理緩沖區的,重新整理後可以再次寫出,隻有字元流才需要重新整理
*b: close()方法
* 用來關閉流釋放資源的的,如果是帶緩沖區的流對象的close()方法,不但會關閉流,還會再關閉流之前重新整理緩沖區,關閉後不能再寫出 關閉流隻用一個最大的那個流進行關閉
5)流的分别講解
5.1) * A: 位元組輸出流FileOutputStream寫位元組
*a: FileOutputStream
*寫入資料檔案,學習父類方法,使用子類對象
*b: FileOutputStream構造方法
*作用:綁定輸出的輸出目的
*FileOutputStream(File file)
*建立一個向指定 File 對象表示的檔案中寫入資料的檔案輸出流。
*FileOutputStream(File file, boolean append)
*建立一個向指定 File 對象表示的檔案中寫入資料的檔案輸出流,以追加的方式寫入。
*FileOutputStream(String name)
*建立一個向具有指定名稱的檔案中寫入資料的輸出檔案流。
*FileOutputStream(String name, boolean append)
* 建立一個向具有指定 name 的檔案中寫入資料的輸出檔案流,以追加的方式寫入。
*c: 流對象使用步驟
* 1. 建立流子類的對象,綁定資料目的
* 2. 調用流對象的方法write寫
* 3. close釋放資源
* d: 注意事項
* 流對象的構造方法,可以建立檔案,如果檔案存在,直接覆寫檔案的内容也進行覆寫
5.2)位元組輸出流FileOutputStream寫位元組數組
*A: 位元組輸出流FileOutputStream寫位元組數組
*a: 方法介紹
* void write(byte[] b):将 b.length 個位元組從指定的 byte 數組寫入此輸出流
* void write(byte[] b, int off, int len) :将指定 byte 數組中從偏移量 off 開始的 len 個位元組寫入此輸出流。
*b: 案例代碼
publicclass FileOutputStreamDemo1 {
publicstatic void main(String[] args)throws IOException {
Filefile = new File("c:\\b.txt");
FileOutputStreamfos = new FileOutputStream(file,true);
fos.write("hello\r\n".getBytes());
fos.write("world".getBytes());
fos.close();
}
}
5.4)位元組輸入流FileInputStream讀取位元組
*A: 位元組輸入流FileInputStream讀取位元組
*a: 方法介紹 沒有追加的說法
*abstract int read() :
*從輸入流中讀取資料的下一個位元組,傳回-1表示檔案結束
*int read(byte[] b)
*從輸入流中讀取一定數量的位元組,并将其存儲在緩沖區數組 b 中。
*讀入緩沖區的位元組總數,如果因為已經到達檔案末尾而沒有更多的資料,則傳回 -1。
*int read(byte[] b, int off, int len)
*将輸入流中最多 len 個資料位元組讀入 byte 數組。
*void close()
*關閉此輸入流并釋放與該流關聯的所有系統資源。
*b: 案例代碼
5.5)字元輸入流讀取文本FileReader類
*A: 字元輸入流讀取文本FileReader類
*a: 方法介紹
* int read()
*讀取單個字元
*int read(char[] cbuf)
*将字元讀入數組
*abstract int read(char[] cbuf, int off,int len)
*将字元讀入數組的某一部分。
*b: 案例代碼
5.6)* a: 轉換流概述
*OutputStreamWriter 是字元流通向位元組流的橋梁:可使用指定的字元編碼表,将要寫入流中的字元編碼成位元組
* 将字元串按照指定的編碼表轉成位元組,在使用位元組流将這些位元組寫出去
OutputStreamWriter寫文本檔案
*A: OutputStreamWriter寫文本檔案
*a: OutputStreamWriter
*java.io.OutputStreamWriter 繼承Writer類
*就是一個字元輸出流,寫文本檔案
* write()字元,字元數組,字元串
*字元通向位元組的橋梁,将字元流轉位元組流
*OutputStreamWriter 使用方式
*構造方法:
*OutputStreamWriter(OuputStream out)接收所有的位元組輸出流
*位元組輸出流: FileOutputStream
*OutputStreamWriter(OutputStream out, String charsetName)
*String charsetName 傳遞編碼表名字 GBK UTF-8
* OutputStreamWriter 有個子類, FileWriter
*b: 案例代碼
publicclass OutputStreamWriterDemo {
publicstatic void main(String[] args)throws IOException {
// writeGBK();
writeUTF();
}
轉換流_位元組轉字元流過程
*A: 轉換流_位元組轉字元流過程
*a: InputStreamReader
*java.io.InputStreamReader 繼承 Reader
*字元輸入流,讀取文本檔案
*位元組流向字元的敲了,将位元組流轉字元流
*讀取的方法:
* read() 讀取1個字元,讀取字元數組
*技巧
*OuputStreamWriter寫了檔案
*InputStreamReader讀取檔案
*OutputStreamWriter(OutputStream out)所有位元組輸出流
*InputStreamReader(InputStream in) 接收所有的位元組輸入流
*可以傳遞的位元組輸入流: FileInputStream
* InputStreamReader(InputStream in,String charsetName) 傳遞編碼表的名字
*b: 圖解
* 詳見day24_source/轉換流.JPG圖檔
* OutputStreamWriter 有個子類, FileWriter
InputStreamReader 有個子類 FileReader
差別
*OutputStreamWriter和InputStreamReader是字元和位元組的橋梁:也可以稱之為字元轉換流。字元轉換流原理:位元組流+編碼表。
*FileWriter和FileReader:作為子類,僅作為操作字元檔案的便捷類存在。
當操作的字元檔案,使用的是預設編碼表時可以不用父類,而直接用子類就完成操作了,簡化了代碼。
* 以下三句話功能相同
* InputStreamReader isr = newInputStreamReader(new FileInputStream("a.txt"));//預設字元集。
* InputStreamReader isr = newInputStreamReader(new FileInputStream("a.txt"),"GBK");//指定GBK字元集。
* FileReader fr = newFileReader("a.txt");
InputSteamReader讀取文本檔案
*A: InputSteamReader讀取文本檔案
*a: 案例代碼
publicclass InputStreamReaderDemo {
publicstatic void main(String[] args) throws IOException {
// readGBK();
readUTF();
}
publicstatic void readUTF()throws IOException{
//建立自己輸入流,傳遞文本檔案
FileInputStreamfis = new FileInputStream("c:\\utf.txt");
//建立轉換流對象,構造方法中,包裝位元組輸入流,同時寫編碼表名
InputStreamReaderisr = new InputStreamReader(fis,"UTF-8");
char[]ch = new char[1024];
intlen = isr.read(ch);
System.out.println(newString(ch,0,len));
isr.close();
}
public static voidreadGBK()throws IOException{
//建立自己輸入流,傳遞文本檔案
FileInputStreamfis = new FileInputStream("c:\\gbk.txt");
//建立轉換流對象,構造方法,包裝位元組輸入流
InputStreamReaderisr = new InputStreamReader(fis);
char[]ch = new char[1024];
int len =isr.read(ch);
System.out.println(newString(ch,0,len));
isr.close();
}
}
5.6)位元組輸出流緩沖流BufferedOutputStream
*A: 位元組輸出流緩沖流BufferedOutputStream
*a: BufferedOutputStream
*位元組輸出流的緩沖流
*java.io.BufferedOuputStream 作用: 提高原有輸出流的寫入效率
*BufferedOuputStream 繼承 OutputStream
*方法,寫入 write 位元組,位元組數組
*構造方法:
*BufferedOuputStream(OuputStream out)
*可以傳遞任意的位元組輸出流, 傳遞的是哪個位元組流,就對哪個位元組流提高效率
5.7)位元組輸入流緩沖流BufferedInputStream
*A: 位元組輸入流緩沖流BufferedInputStream
*a: BufferedInputStream
*位元組輸入流的緩沖流
*繼承InputStream,标準的位元組輸入流
*讀取方法 read() 單個位元組,位元組數組
*構造方法:
*BufferedInputStream(InputStream in)
*可以傳遞任意的位元組輸入流,傳遞是誰,就提高誰的效率
* 可以傳遞的位元組輸入流 FileInputStream)
5.8)字元輸出流緩沖流BufferedWriter
*A: 字元輸出流緩沖流BufferedWriter
*a: BufferedWriter
*字元輸出流緩沖區流
*java.io.BufferedWriter 繼承 Writer
*寫入方法 write () 單個字元,字元數組,字元串
*構造方法:
*BufferedWriter(Writer w)傳遞任意字元輸出流
*傳遞誰,就高效誰
*能傳遞的字元輸出流 FileWriter, OutputStreamWriter
12字元輸出流緩沖流BufferedWriter特有方法newLine
*A: 字元輸出流緩沖流BufferedWriter特有方法newLine
*a: 方法介紹
*void newLine() 寫換行
*newLine()文本中換行, \r\n也是文本換行
*方法具有平台無關性
*Windows \r\n
*Linux \n
*newLine()運作結果,和作業系統是互相關系
*JVM: 安裝的是Windows版本,newLine()寫的就是\r\n
*安裝的是Linux版本,newLine()寫的就是\n
需要掌握流的總結
FileInputStream | FileOutputStream |
InputStreamReader | OutputStreamWriter |
FileReader | FileWriter |
ObjectInputStream | * ObjectOutputStream |
PrintStream PrintWriter | |
DataInputStream | DataOutputStream |
BufferedReader | BufferedWriter |
ByteArrayInputStream | ByteArrayOutputStream |
BufferedInputStream | BufferedOutputStream |
5.11)靜态不能序列化
*A: 靜态不能序列化
*a: 原因
*序列化是把對象資料進行持久化存儲
*靜态的東西不屬于對象,而屬于類
transient關鍵字
*A: transient關鍵字
*a: 作用
*被transient修飾的屬性不會被序列化
*transient關鍵字隻能修飾成員變量
Serializable接口的含義
*A:Serializable接口的含義
*a: 作用
*給需要序列化的類上加标記。該标記中沒有任何抽象方法
*隻有實作了 Serializable接口的類的對象才能被序列化
序列化中的序列号沖突問題
*A: 序列化中的序列号沖突問題
*a: 問題産生原因
*當一個類實作Serializable接口後,建立對象并将對象寫入檔案,之後更改了源代碼(比如:将成員變量的修飾符有private改成public),
再次從檔案中讀取對象時會報異常
*見day25_source檔案夾下的"序列号的沖突.JPG"檔案
序列化中自定義的序列号
*A: 序列化中自定義的序列号
*a: 定義方式
*private static final long serialVersionUID = 1478652478456L;
* 這樣每次編譯類時生成的serialVersionUID值都是固定的
### 對象流
Java 提供了對象流,是處理流,可以簡化對象的IO。對象流要求參與對象序列化的類必須實作序列化接口
> 注意:實作序列化接口的類最好添加序列化版本号 serialVersionUID
> 瞬态關鍵字修飾的屬性在序列化時候被忽略掉。
5.12)列印流和特性
*A: 列印流和特性
*a: 概述
*列印流添加輸出資料的功能,使它們能夠友善地列印各種資料值表示形式.
*列印流根據流的分類:
*位元組列印流 PrintStream
*字元列印流 PrintWriter
*方法:
*void print(String str): 輸出任意類型的資料,
*void println(String str): 輸出任意類型的資料,自動寫入換行操作
*b: 特點
*此流不負責資料源,隻負責資料目的
*為其他輸出流,添加功能
*永遠不會抛出IOException,但是可能抛出别的異常
*兩個列印流的方法,完全一緻
*構造方法,就是列印流的輸出目的端
* PrintStream構造方法
*接收File類型,接收字元串檔案名,接收位元組輸出流OutputStream
*PrintWriter構造方法
* 接收File類型,接收字元串檔案名,接收位元組輸出流OutputStream, 接收字元輸出流Writer
* b: 結果分析
*println數組,隻有列印字元數組時隻有容,其餘均列印數組的位址
*因為api中定義了列印字元數組的方法,其底層是在周遊數組中的元素
* 而其他列印數組的方法,都是将數組對象程式設計Object,其底層再将對象程式設計String,調用了String s = String.valueOf(x);方法
PrintWriter(File file) 使用指定檔案建立不具有自動行重新整理的新 PrintWriter。 |
PrintWriter(File file, String csn) 建立具有指定檔案和字元集且不帶自動刷行新的新 PrintWriter。 |
PrintWriter(OutputStream out) 根據現有的 OutputStream 建立不帶自動行重新整理的新 PrintWriter。 |
PrintWriter(OutputStream out, boolean autoFlush) 通過現有的 OutputStream 建立新的 PrintWriter。 |
PrintWriter(String fileName) 建立具有指定檔案名稱且不帶自動行重新整理的新 PrintWriter。 |
PrintWriter(String fileName, String csn) 建立具有指定檔案名稱和字元集且不帶自動行重新整理的新 PrintWriter。 |
PrintWriter(Writer out) 建立不帶自動行重新整理的新 PrintWriter。 |
PrintWriter(Writer out, boolean autoFlush) 建立新 PrintWriter。 |
* 列印流,可以開啟自動重新整理功能
* 滿足2個條件:
* 1. 輸出的資料目的必須是流對象
* OutputStream Writer
* 2. 必須調用println,printf,format三個方法中的一個,啟用自動重新整理
6 字元節點流可以直接連資料源的(不能和位元組節點流連用) 字元處理流隻能套結在字元節點流或者字元處理流上 (而轉換流除外)它可以把字元節點流轉化成字元處理流轉化流也可以套結在位元組處理流上把()
printWriter() 裡面封裝了可以直接放檔案名具體的看構造函數
publicPrintWriter(String fileName) throws FileNotFoundException {
this(new BufferedWriter(new OutputStreamWriter(newFileOutputStream(fileName))),
false);
}
7 RamdomAccessFile 與流
7.1. RamdomAccessFile 可以随機通路(可以在檔案的任何位置開始讀寫),而流隻能單向讀寫,讀寫過去就不能傳回頭重寫讀寫了。流讀寫是分開的兩個類型。
7.2. 流是一套可以擴充的體系,提供了無限的擴充功能流。而RAF隻能出來byte資料和基本類型資料。RAF功能沒有提供豐富擴充功能。
### 節點流與處理流
- **節點流**:是連接配接到資料源進行最基本的IO功能的流,是其他處理流的基礎。
- **處理流**:是流的功能擴充,有很多處理流,展現了流的豐富擴充功能。處理流因為是基于其他流進行的擴充功能,是以處理流不能單獨工作,必須依賴其他的流。
按照功能不同分為節點流和處理流
節點流連接配接資料源的
處理流是節點流之上的處理流套結在節點流或者處理流之上的
IO流得操作都是從頭到尾得不能通過指針來定位 寫的時候
1 PrintWriter(String fileName, String csn)
建立具有指定檔案名稱和字元集且不帶自動行重新整理的新 PrintWriter。
2 PrintWriter(File file)
使用指定檔案建立不具有自動行重新整理的新 PrintWriter。
3
PrintWriter(String fileName) 建立具有指定檔案名稱且不帶自動行重新整理的新 PrintWriter。 |
8 編碼表
* A: 編碼表
* a: 定義:
* 生活中字元和計算機二進制的對應關系表,就是編碼表
* b: 分類
* 1、ascii: 一個位元組中的7位就可以表示。對應的位元組都是正數。0-xxxxxxx
* 2、iso-8859-1:拉丁碼表 latin,用了一個位元組用的8位。1-xxxxxxx 負數。
* 3、GB2312:簡體中文碼表。包含6000-7000中文和符号。用兩個位元組表示。兩個位元組第一個位元組是負數,第二個位元組可能是正數
* GBK:目前最常用的中文碼表,2萬的中文和符号。用兩個位元組表示,其中的一部分文字,第一個位元組開頭是1,第二位元組開頭是0
* GB18030:最新的中文碼表,目前還沒有正式使用。
* 4、unicode:國際标準碼表:無論是什麼文字,都用兩個位元組存儲。
* Java中的char類型用的就是這個碼表。char c = 'a';占兩個位元組。
* Java中的字元串是按照系統預設碼表來解析的。簡體中文版 字元串預設的碼表是GBK。
* 5、UTF-8:基于unicode,一個位元組就可以存儲資料,不要用兩個位元組存儲,而且這個碼表更加的标準化,在每一個位元組頭加入了編碼資訊(後期到api中查找)。
* 6、能識别中文的碼表:GBK、UTF-8;正因為識别中文碼表不唯一,涉及到了編碼解碼問題。
* 對于我們開發而言;常見的編碼 GBK UTF-8 ISO-8859-1
* 文字--->(數字) :編碼。“abc”.getBytes() byte[]
* (數字)--->文字 : 解碼。 byte[]b={97,98,99} new String(b)
9流對象的操作規律
* A: IO流對象的操作規律
* a: 明确一:要操作的資料是資料源還是資料目的。
* 源:InputStream Reader
* 目的:OutputStreamWriter
* 先根據需求明确要讀,還是要寫。
* b: 明确二:要操作的資料是位元組還是文本呢?
* 源:
* 位元組:InputStream
* 文本:Reader
* 目的:
* 位元組:OutputStream
* 文本:Writer
* c: 明确三:明确資料所在的具體裝置。
* 源裝置:
* 硬碟:檔案 File開頭。
* 記憶體:數組,字元串。
* 鍵盤:System.in;
* 網絡:Socket
* 目的裝置:
* 硬碟:檔案 File開頭。
* 記憶體:數組,字元串。
* 螢幕:System.out
* 網絡:Socket
* 完全可以明确具體要使用哪個流對象。
* d: 明确四:是否需要額外功能呢?
* 額外功能:
* 轉換嗎?轉換流。InputStreamReader OutputStreamWriter
* 高效嗎?緩沖區對象。BufferedXXX
* 已經明确到了具體的體系上。