IO流輸入輸出流,字符字節流


 一、流

1.流的概念
流是一組有順序的,有起點和終點的字節集合,是對數據傳輸的總稱或抽象。即數據在兩設備間的傳輸稱為流,流的本質是數據傳輸,根據數據傳輸特性將流抽象為各種類,方便更直觀的進行數據操作。
2.流的分類
根據處理數據類型的不同分為:字符流和字節流,字符流處理的單元為 2 個字節的 Unicode 字符,分別操作字符、字符數組或字符串,而字節流處理單元為 1 個字節,操作字節和字節數組。
根據數據流向不同分為:輸入流和輸出流

3.字符流和字節流
3.1 字符流的由來: 因為數據編碼的不同,而有了對字符進行高效操作的流對象。本質其實就是基於字節流讀取時,去查了指定的碼表。 Java 內用 Unicode 編碼存儲字符,字符流處理類負責將外部的其他編碼的字符流和 java 內 Unicode 字符流之間的轉換。
3.2 字節流和字符流的區別:
(1)讀寫單位不同:字節流以字節(8bit)為單位,字符流以字符為單位,根據碼表映射字符,一次可能讀多個字節。
(2)處理對象不同:字節流能處理所有類型的數據(如圖片、avi等),而字符流只能處理字符類型的數據。
(3)字節流在操作的時候本身是不會用到緩沖區的,是文件本身的直接操作的;而字符流在操作的時候下后是會用到緩沖區的,是通過緩沖區來操作文件,我們將在下面驗證這一點。

結論:優先選用字節流。首先因為硬盤上的所有文件都是以字節的形式進行傳輸或者保存的,包括圖片等內容。但是字符只是在內存中才會形成的,所以在開發中,字節流使用廣泛。從效率而言,字符流(一次可以處理一個緩沖區)一次操作比字節流(一次一個字節)效率高。

4.輸入流和輸出流
對輸入流只能進行讀操作,對輸出流只能進行寫操作,程序中需要根據待傳輸數據的不同特性而使用不同的流。輸入輸出流的流向是相對於程序而言。
輸入流:InputStream 讀入 就是從外部文件中讀取數據到程序。對應 Reader;
輸出流: OutputStream 寫出 就是將數據從程序寫入到外部文件。對應 Writer;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

二、字節流

1.字節流概述
1)字節流和字符流的基本操作是相同的,但是要想操作媒體流就需要用到字節流。
2)字節流因為操作的是字節,所以可以用來操作媒體文件。(媒體文件也是以字節存儲的)
3)讀寫字節流:InputStream 輸入流(讀)和OutputStream 輸出流(寫)
4)字節流操作可以不用刷新流操作。
5)InputStream特有方法:
int available(); //返回文件中的字節個數

注:可以利用此方法來指定讀取方式中傳入數組的長度,從而省去循環判斷。但是如果文件較大,而虛擬機啟動分配的默認內存一般為64M。當文件過大時,此數組長度所占內存空間就會溢出。所以,此方法慎用,當文件不大時,可以使用

2. 字節流緩沖區
1)緩沖區的出現時為了提高流的操作效率而出現的.
2)需要被提高效率的流作為參數傳遞給緩沖區的構造函數
3)在緩沖區中封裝了一個數組,存入數據后一次取出

3.輸入字節流InputStream
定義和結構說明:
從輸入字節流的繼承圖可以看出:InputStream 是所有的輸入字節流的父類,它是一個抽象類。
ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三種基本的介質流,它們分別從Byte 數組、StringBuffer、和本地文件中讀取數據。
PipedInputStream 是從與其它線程共用的管道中讀取數據,與Piped 相關的知識后續單獨介紹。
ObjectInputStream 和所有FilterInputStream的子類都是裝飾流(裝飾器模式的主角)。意思是FileInputStream類可以通過一個String路徑名創建一個對象,FileInputStream(String name)。
DataInputStream必須裝飾一個類才能返回一個對象,DataInputStream(InputStream in)。

public static void main(String[] args) throws IOException { 
  File f=new File("aaa.txt"); //定位文件位置
  InputStream in=new FileInputStream(f); //創建字節輸入流連接到文件
  byte[] b=new byte[1024]; //定義一個數組,用來存放讀入的數據 byte數組的大小也可以根據文件大小來定 (int)f.length()
  int count =0; 
  int temp=0;
  while((temp=in.read())!=(-1)){ //in.read()是逐字節讀的。當讀到文件末尾時候返回-1
    b[count++]=(byte)temp; //將讀到的字節存儲到byte數組中 
  }
  in.close(); //關閉流
  System.out.println(new String(b)); //打印讀取到的字節
}

注意:當讀到文件末尾的時候會返回-1.正常情況下是不會返回-1的。


加入字節緩沖輸入流,提高了讀取效率

public static void main(String[] args) throws IOException { 
  File f=new File("aaa.txt"); //定位文件位置
  InputStream in=new FileInputStream(f); //創建字節輸入流連接到文件
  BufferedInputStream bis=new BufferedInputStream(in); //創建緩沖字節流
  byte[] b=new byte[1024]; //定義一個數組,用來存放讀入的數據 byte數組的大小也可以根據文件大小來定 (int)f.length()
  int count =0; 
  int temp=0;
  bis.read();
  while((temp=bis.read())!=(-1)){ //in.read()是逐字節讀的。當讀到文件末尾時候返回-1
    b[count++]=(byte)temp; //將讀到的字節存儲到byte數組中 
  }
  bis.close(); //關閉緩沖字節流
  in.close(); //關閉流
  System.out.println(new String(b)); //打印讀取到的字節
}

 

4.輸出字節流OutputStream

定義和結構說明:

IO 中輸出字節流的繼承圖可見上圖,可以看出:OutputStream 是所有的輸出字節流的父類,它是一個抽象類。
ByteArrayOutputStream、FileOutputStream是兩種基本的介質流,它們分別向Byte 數組、和本地文件中寫入數據。
PipedOutputStream 是向與其它線程共用的管道中寫入數據,
ObjectOutputStream 和所有FilterOutputStream的子類都是裝飾流。具體例子跟InputStream是對應的。

public static void main(String[] args) throws IOException {
  File f = new File("aaa.txt"); // 定位文件位置
  OutputStream out = new FileOutputStream(f); // 創建字節輸出流連接到文件
  String str = "hhhhhhh"; 
  byte[] b = str.getBytes(); //講數據存入byte數組
  out.write(b); //寫數據 
  out.close(); //關閉流
}

加入字節緩沖輸入流,提高了讀取效率

 

public static void main(String[] args) throws IOException {
  File f = new File("aaa.txt"); // 定位文件位置
  OutputStream out = new FileOutputStream(f); // 創建字節輸出流連接到文件
  BufferedOutputStream bos=new BufferedOutputStream(out);
  String str = "hhhhhhh"; 
  byte[] b = str.getBytes(); //講數據存入byte數組
  bos.write(b); //寫數據 
  bos.close(); //關閉緩沖流
  out.close(); //關閉流
}

5.幾個特殊的輸入流類分析

LineNumberInputStream
主要完成從流中讀取數據時,會得到相應的行號,至於什么時候分行、在哪里分行是由改類主動確定的,並不是在原始中有這樣一個行號。在輸出部分沒有對應的部分,我們完全可以自己建立一個LineNumberOutputStream,在最初寫入時會有一個基准的行號,以后每次遇到換行時會在下一行添加一個行號,看起來也是可以的。好像更不入流了。

PushbackInputStream
其功能是查看最后一個字節,不滿意就放入緩沖區。主要用在編譯器的語法、詞法分析部分。輸出部分的BufferedOutputStream 幾乎實現相近的功能。

StringBufferInputStream

已經被Deprecated,本身就不應該出現在InputStream部分,主要因為String 應該屬於字符流的范圍。已經被廢棄了,當然輸出部分也沒有必要需要它了!還允許它存在只是為了保持版本的向下兼容而已。

SequenceInputStream
可以認為是一個工具類,將兩個或者多個輸入流當成一個輸入流依次讀取。完全可以從IO 包中去除,還完全不影響IO 包的結構,卻讓其更“純潔”――純潔的Decorator 模式。

三、字符流

1.字符輸入流Reader
定義和說明:

在上面的繼承關系圖中可以看出:Reader 是所有的輸入字符流的父類,它是一個抽象類。
CharReader、StringReader是兩種基本的介質流,它們分別將Char 數組、String中讀取數據。
PipedReader 是從與其它線程共用的管道中讀取數據。
BufferedReader 很明顯就是一個裝飾器,它和其子類負責裝飾其它Reader 對象。
FilterReader 是所有自定義具體裝飾流的父類,其子類PushbackReader 對Reader 對象進行裝飾,會增加一個行號。
InputStreamReader 是一個連接字節流和字符流的橋梁,它將字節流轉變為字符流。FileReader可以說是一個達到此功能、常用的工具類,在其源代碼中明顯使用了將FileInputStream 轉變為Reader 的方法。我們可以從這個類中得到一定的技巧。Reader 中各個類的用途和使用方法基本和InputStream 中的類使用一致。后面會有Reader 與InputStream 的對應關系。

public static void main(String[] args) throws IOException {    
    File f = new File("aaa.txt"); // 定位文件位置
    char[] ch = new char[100]; //定義一個數組,用來存放讀入的數據
    Reader read = new FileReader(f); //創建字符輸入流連接到文件
    int count = read.read(ch); //讀操作
    read.close(); //關閉流
    System.out.println("讀入的長度為:" + count);
    System.out.println("內容為" + new String(ch, 0, count));
}

 

加入緩沖流 提高效率。

public static void main(String[] args) throws IOException {    
    File f = new File("aaa.txt"); // 定位文件位置
    char[] ch = new char[100]; //定義一個數組,用來存放讀入的數據
    Reader read = new FileReader(f); //創建字符輸入流連接到文件
    BufferedReader bfr=new BufferedReader(read); //創建緩沖流
    int count = bfr.read(ch); //讀操作
    bfr.close(); //關閉緩沖流
    read.close(); //關閉流
    System.out.println("讀入的長度為:" + count);
    System.out.println("內容為" + new String(ch, 0, count));
}

2.字符輸出流Writer

定義和說明:

在上面的關系圖中可以看出:Writer 是所有的輸出字符流的父類,它是一個抽象類。
CharArrayWriter、StringWriter 是兩種基本的介質流,它們分別向Char 數組、String 中寫入數據。
PipedWriter 是向與其它線程共用的管道中寫入數據,
BufferedWriter 是一個裝飾器為Writer 提供緩沖功能。
PrintWriter 和PrintStream 極其類似,功能和使用也非常相似。
OutputStreamWriter 是OutputStream 到Writer 轉換的橋梁,它的子類FileWriter 其實就是一個實現此功能的具體類(具體可以研究一SourceCode)。功能和使用和OutputStream 極其類似。

public static void main(String[] args) throws IOException {    
    File f=new File("aaa.txt"); // 定位文件位置
    Writer out =new FileWriter(f); //創建字符輸出流連接到文件
    String str="哈哈哈哈哈哈"; 
    out.write(str); //寫操作 
    out.close(); //關閉流    
}

加入緩沖流 提高效率。

public static void main(String[] args) throws IOException {    
    File f=new File("aaa.txt"); // 定位文件位置
    Writer out =new FileWriter(f); //創建字符輸出流連接到文件
    BufferedWriter bfw =new BufferedWriter(out); //創建緩沖流
    String str="哈哈哈哈哈哈"; 
    bfw.write(str); //寫操作 
    bfw.close(); //關閉緩沖流
    out.close(); //關閉流
}

四、字符流與字節流轉換

轉換流的特點:
(1)其是字符流和字節流之間的橋梁
(2)可對讀取到的字節數據經過指定編碼轉換成字符
(3)可對讀取到的字符數據經過指定編碼轉換成字節
何時使用轉換流?
當字節和字符之間有轉換動作時;
流操作的數據需要編碼或解碼時。
具體的對象體現:
InputStreamReader:字節到字符的橋梁
OutputStreamWriter:字符到字節的橋梁
這兩個流對象是字符體系中的成員,它們有轉換作用,本身又是字符流,所以在構造的時候需要傳入字節流對象進來。

 

/**
* 將字節輸出流轉化為字符輸出流
* */
public
static void main(String[] args) throws IOException { File file=new File("aaa.txt"); Writer out=new OutputStreamWriter(new FileOutputStream(file)); out.write("hello"); out.close(); }
/**
* 將字節輸入流變為字符輸入流
* */

public static void main(String[] args) throws IOException {
    File file=new File("aaa.txt"); 
    Reader read=new InputStreamReader(new FileInputStream(file));
    char[] b=new char[100];
    int len=read.read(b);
    System.out.println(new String(b,0,len));
    read.close();
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM