黑馬程序員-第十九天( IO(Input Output)流)

---------------------- ASP.Net+Unity開發.Net培訓、期待與您交流! ----------------------

                                                            IO(Input Output)流


一、IO流作用
IO流用來處理設備之間的數據傳輸
java對數據的操作是通過流的方式
java用於操作流的對象都在IO包中

二、流的分類
流按操作數據分爲兩種:字節流和字符流。字節流可以融入編碼表,可以自己指定編碼表。字節流是通用的,字符流是基於字節流的。
流按流向分爲:輸入流和輸出流。 

三、編碼表
ASCII(一個字節):美國編碼表
GBK(兩個字節):中國編碼表
UnCode(兩個字節表示):國際編碼表  後來優化成UTF-8(所佔字節自動分配)      

亂碼:一個格式的編碼方式進行存儲,然後以另一種編碼方式進行讀取,這樣會導致亂碼                                      


四、IO流常用基類
·字節流的抽象基類:
InputStream (讀)  OutputStream(寫)
·字符流的抽象基類:
Reader(讀)  Writer(寫)   

注: 由這四個類派生出來的子類名稱都是以其父類名作爲子類名的後綴。前綴名是對象的功能。如:
InputStream 的子類 FileInputStream
Reader 的子類 FileReader。


五、FileWriter

1,方法 (這些方法都會拋出IOException異常):
void writer(int ch);寫入單個的字符            
void writer(char[] arr);寫入一個字符數組 
void writer(char[] ,int off,int len);將指定字符數組中的一部分進行寫入
void writer (String str);寫入一個字符串
vois writer (String str,int off,int len);將字符串的指定部分進行寫入
void flush()刷新該流的緩衝
void close()關閉此流,但要先刷新它(其實就是先調用flush()方法刷新一次,然後又調用底層關閉流的方法)

既然IO流是用於操作數據的,那麼數據的最常見體現形式是:文件。

2,子類 FileWriter
創建一個FileWriter對象,該對象一被初始化就必須要明確被操作的文件,而且該文件會被創建到指定目錄下,
如果該目錄下已有同名文件,將被覆蓋。
如:
1,FileWriter fileWriter = new FileWriter("Demo.txt");
jvm執行完此語句時,會在堆內存中建立一個FileWriter對象,並在當前目錄下建立一個Demo.txt文件如果些文件存在
將會被覆蓋。 其實該步就是在明確數據要存放的目的地 
2,調用write方法,將字符串寫入到流中。
fileWriter.write("abcde");
3, 刷新流對象中的緩衝中的數據,將數據刷到目的地中
fileWriter.flush();
4,關閉流資源,但關閉之前會刷新一次內部的緩衝區中的數據,將數據刷到指定的位置 
fileWriter.close();


六,對IO異常的處理

對其進行捕捉和處理。如下程序:
public class FileWriterDemo{

public static void main(String[] args){

//在try外面建立對象的引用 
FileWriter fw = null;
try{

fw = new FileWriter("Test.txt");
fw.write("heihie");
}
catch(IOException io){

System.out.println(io);
}
//一定要執行的動作關閉資源
finally{

try{

if(fw != null)
fw.close();
}
catch(IOException io){

System.out.println(io);
}

}
}
}


七、文本數據的續寫
構造函數:
FileWriter(String name,boolean apped):    根據給定的文件名以及指示是否附加寫入數據的 boolean 值來構造 FileWriter 對象。
當傳遞一個true參數,代表不覆蓋已有的文件,並在已有文件的未尾處進行數據續寫


換行: ·在window中換行用:\r\n (wind中的記事本只能識別\r\n) 
·在Linux中換行用:\n
 
八、文本文件讀取方式:

1,Reader中的方法:
abstract void close():關閉該流並釋放與之關聯在所有資源
void mark(int readAheadLimit) 標記流中的當前位置
boolean markSupported()判斷此流是否支持mark()操作
int read()讀取單個字符。返回字符的ASCII值,如果已到達流的未尾時,則返回-1
int read(char[] buf)將字符讀入數組
abstract int read(char[] buf,int off,int len)將字符讀入數組的某一部分
int read(CharBuffer target) 將字符讀入指定的字符緩衝區
boolean ready():判斷是否準備讀取此流
void reset():重置該流
long skip(long n)路過字符

注:read()方法一次讀一個字符,而且會自動向下讀
2,FileReader 
·構造函數 :
FileReader(String name)
FileReader(File file)
·建立讀取流步驟

方法一(read()方法):
public static void main(String[] args){

//在try塊的外面建立讀取流的引用 
FileReader fr = null;

try{

//讓讀取流與一個文件進行關聯
fr = new FileReader("hehe.txt");
int ch = 0;
//循環的來讀取文件中的字符 
while((ch = fr.read()) != -1){

System.out.println((char)ch);
}
catch(FileNotFoundException ex){

System.out.println("沒有找到要讀取的文件");
throw new RuntimeException();
}
catch(IOException e){

throw new RuntimeException();
}
finalyy{

try{
//判斷此引用是不是爲空,如不爲null關閉資源
if(fr != null)
fr.close();
}
catch(IOException io){

throw new RuntimeException("流資源關閉失敗");
}
}
}
}
方法二,使用read(char[] buf)來讀取
public static void readMethodTwo(){

FileReader fr = null;

try{
//與文件進行關聯
fr =  new FileReader("Test.txt") ;
char[] buf = new char[1024];
int num = 0;
while((num = fr.read(buf)) != -1){

System.out.println(new String(buf,0,num)) ;
}

}
catch(IOException io) {

throw new RuntimeException("出問題") ;
}
finally{

try{
//先判斷下是否爲空,如不爲空關閉流資源
if(fr != null)
fr.close();
}
catch(IOException io){

throw new RuntimeException();
}
}
}
3,複製的原理:
其實就是將某盤(c盤)下的文件數據存儲到另一個盤(d盤)的一個文件中

步驟:
1,在d盤下創建一個文件,用於存儲c盤文件中的數據。
2,定義讀取流和c盤文件進行關聯。
3,通過不斷的讀寫完成數據的存儲。
4,關閉流資源
 
九、字符流的緩衝區
1,緩衝區的出現提高了流對數據的讀寫效率,而出現的,所有在創建緩衝區之前,必須要先有流對象
2,對應類
BufferedWriter
中的newLine()是一個跨平臺的換行符
BufferedReader
中的String readLine()讀出一行數據 ,不會讀取換行符的。

3,緩衝區的關閉其實就是關閉它所提高效率的流對象,

十,readLine的原理:
無論是讀一行,獲取讀取多個字符,其實最終都是在在硬盤上一個一個讀取。所以最終使用的還是read方法
一次讀一個的方法,只過就是先存放在一個容器裏,當讀到換行符時,纔會返回。

十一,LineNumberReader(BuffferedReader的子類)


1,此類是獲取或設置行號的一個包裝類
2,特有方法:
int getLineNumber():獲取行號
void setLineNumber(int) :設置行號

十二,字節流
InputStream:字節讀取流
OutputStream:字節寫入流

1.OutputStream中的方法(不需要刷新)
void close();關閉此流關聯的資源
void flush();刷新此輸出流並強制寫出所有緩衝的輸出字節
void  write(byte[] byte);將byte數組定入此輸出流。
void write(byte[]b,int off,int len);將指定byte數組中從偏移量off開始的len個字節寫入此輸出流
void write(int b)將指定的字節寫入此輸出流

2,InputStream中的方法:
int available(); 返回這個文件的大小。(\r\n佔兩個字節)可以根據返回值定義一個剛剛大小的數組(存放臨時讀取的字節)
int read();讀取一個字節並返回
int read(byte[] byte):將字節讀取到byte數組中返回讀取的個數
3,字節流中的read方法返回值爲什麼不是byte類型?
因爲字節流在讀取數據時都是二進制的數據,有可能會讀到連續8個1的情況,,這時程序會返回-1,也就是read方法結束的標誌,如果返回是
int類型時,系統會自動進行類型提升但是,-1進行提升時還會是-1,所以這時爲了保留原來的8位,,就要&255這樣可以保留最低8位了,
而當寫入一個字節時,,write方法會自動將int類型的數據強制轉換成byte類型數據進行寫入,所以複製後的文件大小不會改變。

4,BufferedInputStream中的read方法的原理?
BufferedInputStream中的read方法是利用傳入的InputStream對象中的read方法將數據讀到一個臨時的數組中,然後,在從數組一個一個
的向外讀取。也就是說調用傳入對象 中的read方法將一個數據讀取到指定的數組中的,然後在數組中一個一個的讀取,當數組中的數據都
讀完時,再去讀取一批數據到數組中,如此循環。


十三,鍵盤錄入


System.out:對應的是標準輸出設備:控制檯
System.in:對應的是標準輸入設備:鍵盤

1,read方法是一種阻塞式方法。

2,轉換流:
將字節流轉換成字符流,在構造函數類型是字節流對象
InputStreamReader:
將字符流轉換成字節流。
OutputStreamWriter:
3,代碼:
package io;
import java.io.*;


public class KeyBoardInputDemo{

public static void main(String[] args){

inputDemo();
}
public static void inputDemo(){

BufferedReader bufr = null;

try{

bufr = new BufferedReader(new InputStreamReader(System.in)) ;

String str = null;

while((str = bufr.readLine()) != null){

if("over".equals(str))
break;

System.out.println(str.toUpperCase());
}
}
catch(IOException e){

throw new RuntimeException("鍵盤錄入出問題了,");
}
finally{

try{

if(bufr != null)
bufr.close();
}
catch(IOException i){

throw new RuntimeException("關閉流失敗!") ;
}
}

}
}
十三。流操作的規律:
通過三個明確來完成
1,明確源和目的:
源:  輸入流   InputStream   Reader
目的:輸出流   OutputStream  Writer

2,操作的數據是否是純文本:
是:   字符流
不是: 字節流

3,當體系明確後,在明確要使用哪 個具體的對象通過設備來進行區分。
源設備:內存,硬盤,鍵盤 
目的設備:內存,硬盤,控制檯

4,是否需要提高效率?
是:加入緩衝技術

5,轉換流什麼時候使用?
轉換流 是字符和字節之間的橋樑,通常,涉及到字符編碼轉換時,需要用到轉換流

6,改變標準的輸入輸出設備:
System.setIn(InputStream in);
System.setOut(PrintStream  out)

---------------------- ASP.Net+Unity開發.Net培訓、期待與您交流! ----------------------

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章