J2SE知識點歸納筆記(七)---Java IO Part 3:基本位元組流,j2se---java

來源:互聯網
上載者:User

J2SE知識點歸納筆記(七)---Java IO Part 3:基本位元組流,j2se---java

J2SE知識點歸納筆記(七)---Java IO Part 3:基本位元組流

                                                                ——轉載請註明出處:coder-pig


本節引言:


在上一節中我們學習了控制台輸入資料的方法以及對Java IO流體系圖進行了初步的瞭解,

在本節中我們針對性地學習一些基本位元組流與字元流的使用~開始本節內容:




1.InputStream與OutputStream的相關方法:

首先要說一點的是:這兩個類是抽象類別,通過子類來實現各種功能;

資料單位為位元組(1 byte = 8bit);下面是相關的方法:


1)InputStream的相關方法:

①public abstract int read( ):讀取一個byte的資料,返回值是高位補0的int類型值;

                                         若返回值=-1說明沒有讀取到任何位元組讀取工作結束。

②public int read(byte b[ ]):讀取b.length個位元組的資料放到b數組中。返回值是讀取的位元組數。
                                 如果流位於檔案末尾不在有資料可用,返回-1;等同於read(b,0,b.length)

③public int read(byte b[ ], int off, int len):從輸入資料流中最多讀取len個位元組的資料,存放到位移量為off的b數組中,

                                 如果流位於檔案末尾不在有資料可用,返回-1;

④public int available( ):返回輸入資料流中可以讀取的位元組數

                                   ps:若輸入阻塞,當前線程將被掛起,如果InputStream對象調用這個方法的話,它只會返回0,

                                   這個方法必須由繼承InputStream類的子類對象調用才有用

⑤public int close( ):使用完畢後,關閉流

⑥public long skip(long n):忽略輸入資料流中的n個位元組,返回值是實際忽略的位元組數,跳過一些位元組來讀取

⑦public void mark(int readlimit):在此輸入資料流中標記當前位置,如果後續調用reset方法會在最後標記的位置重新置放

                                  此流,以便後續讀取重新讀取相同的位元組,另外參數:readlimit代表:標記失效錢允許讀取的位元組數

                                  ps:jdk 1.6後貌似沒限制多少個位元組~

⑧public void reset( ):將流重新置放到最後一次調用mark方法的位置!

⑨public boolean markSupported( ):判斷該輸入資料流是否支援mark和reset方法


ps:這裡的mark和reset方法,你們可能不是很明白,後面學習BufferedInputStream的時候,

會給大家寫個例子,到時你就知道這兩個玩意的作用了...

還有,雖然read有三種不同的構造方法,但是建議使用後面兩個,第一個少用!!!



2)OutputStream的相關方法:

①public void close( ):關閉此輸出資料流並釋放與此流有關的所有系統資源

②public void flush( ):重新整理此輸出資料流並強制寫出所有緩衝的輸出位元組

③public abstract void write(int b):將指定的位元組寫入此輸出資料流

public void write(byte[] b):將 b.length個位元組從指定的byte數組寫入此輸出資料流

⑤public void write(byte[] b,int off,int len):將指定 byte 數組中從位移量 off 開始的 len 個位元組寫入此輸出資料流



ps:其實這些方法,直接查文檔都可以查出來的,筆者也是貼的api上的解析而已~

    所以遇到不會用,沒見過的方法,先查文檔~




2.FileInputStream與FileOutputStream類的使用:

先來介紹位元組流的第一個子類:ileInputStream與FileOutputStream類吧!

見名知意:就是以位元組的形式對檔案進行讀寫操作;

這裡就不貼相關方法了,自行查閱API文檔吧,直接上執行個體:


代碼執行個體:實現檔案複製

/* * 該方法用於複製檔案,是最簡單的,沒有加入緩衝機制,所以很垃圾~只是方便讀者理解 * 參數以此是:被複製檔案的完整路徑,以及複製後產生的檔案的完整路徑 * */public static void copyFile1(String file1,String file2) throws IOException{File file = new File(file1);File outfile = new File(file2);FileInputStream inputStream = new FileInputStream(file);FileOutputStream outputStream = new FileOutputStream(outfile);int i = 0;while(i != -1) {i = inputStream.read();outputStream.write(i);}//記得關閉流inputStream.close();outputStream.close();}

運行:



好了,上述的代碼,如果複製的是大檔案,就呵呵了,等死你...所以我們需要加入緩衝區,

以便提高檔案的複製速度,就是添加一個位元組緩衝數組而已~

代碼也很簡單:

/* * 該方法在1的基礎上,添加了byte[]數組緩衝機制,複製大檔案的時候,他的優勢就顯現出來了~ */public static void copyFile2(String file1, String file2) throws IOException {File file = new File(file1);File outfile = new File(file2);FileInputStream inputStream = new FileInputStream(file);FileOutputStream outputStream = new FileOutputStream(outfile);int i = 0;//設定緩衝的位元組數組為緩衝512 bytebyte[] buffer = new byte[512];while (true) {if (inputStream.available() < 512) {while (i != -1) {i = inputStream.read();outputStream.write(i);}break;} else {// 當檔案的大小大於512 byte時inputStream.read(buffer);outputStream.write(buffer);}}// 記得關閉流inputStream.close();outputStream.close();}


代碼解析:

就是添加一個512byte的字元數組,但是速度卻明顯提高了,不信麼?

你可以找個大檔案試試,比如筆者這裡用的美圖秀秀,差不多30M,用1中的

方法,過了差不多1分多鐘才複製完畢,而用加了緩衝的幾秒鐘就複製好了~




3)ByteArrayInputStream與ByteArrayOutputStream類的使用:

見名知意:位元組數組的位元組流,建立執行個體是程式內部會建立一個byte型數組的緩衝區,

在網路傳輸的時候用的比較多,這裡給獲得某個頁面的網頁原始碼~

ByteArrayOutputStream用得比較多,另外toByteArray( )方法很常用

你也可以自行擴充,比如,訪問的url是圖片,然後把圖片儲存到本地~


代碼執行個體:

/* * 獲得某個網頁原始碼: * 參數是一個網頁的連結: * */public static String getHtml(String path)throws Exception{URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setConnectTimeout(5000);conn.setRequestMethod("GET");if(conn.getResponseCode() == 200){InputStream in = conn.getInputStream();ByteArrayOutputStream out = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len = 0;while((len = in.read(buffer)) != -1){out.write(buffer,0,len);}in.close();byte[] data = out.toByteArray();String html = new String(data,"UTF-8");return html;}return null;}


運行:


好了,這樣就讀取到一個網頁的原始碼了~





4)ObjectInputStream與ObjectOutputStream類 

見名知意,對象位元組流,就是可以直接把對象轉換為流,另外,轉換的對象對應的類,

需要實現Serializable介面,另外對象中的transient和static類型成員變數不會被讀取和寫入

下面我們來寫個簡單的程式碼範例:


step 1:定義一個業務Bean:

import java.io.Serializable;public class Book implements Serializable {private String bName;private String bReporter;public Book(String bName, String bReporter) {super();this.bName = bName;this.bReporter = bReporter;}public String getbName() {return bName;}public void setbName(String bName) {this.bName = bName;}public String getbReporter() {return bReporter;}public void setbReporter(String bReporter) {this.bReporter = bReporter;}}


step 2:先構造低級流FileOutputStream和FileInputStream,然後才能使用

ObjectOutputStream與ObjectInputStream:


public static void main(String[] args) throws Exception {Book b1 = new Book("《如何與傻B相處》", "豬小豬");Book b2 = new Book("《逗比的自我修養》", "貓小貓");Book b3,b4;//注意:使用進階流需要先構造低級流//①把對象直接寫入到檔案中FileOutputStream fout = new FileOutputStream("D:/books.txt");ObjectOutputStream out = new ObjectOutputStream(fout);out.writeObject(b1);out.writeObject(b2);//關閉輸出資料流out.close();//②讀取檔案中的對象:FileInputStream fin=new FileInputStream("D:/books.txt");ObjectInputStream in=new ObjectInputStream(fin);    b3=(Book) in.readObject();    b4=(Book) in.readObject();    //關閉輸入資料流    in.close();    System.out.println(b3.getbName() + " 作者: "+ b3.getbReporter());    System.out.println(b4.getbName() + " 作者: "+ b4.getbReporter());}


運行:



同時,我們可以在D盤下看到這個book.txt的檔案,但是開啟後是亂碼,

這是因為,我們寫入的是位元組流~中文就會出現亂碼,如果想解決這種情況,

可以使用後面會說的FileWriter和FileReader~






5)PipedOutputStream與PipedInputStream類

這個是管道流,相比起前面的介紹的幾個流,這個就稍微複雜點了,

通過這兩個流可以讓多線程通過管道進行線程間的通訊,兩者需要搭配使用哦!

不同於Linux和Unix系統中的管道,他們是不同地址空間空間的兩個進程可以通過管道通訊,

Java中則是運行在同一進程中的不同線程!

原理:PipedInputStream內部有一個Buffer,使用InputStream的方法讀取其Buffer中的位元組;

而Buffer中的位元組是PipedOutputStream調用PipedInputStream的方法放入的;

另外,不建議把這兩個流對應的對象寫在同一線程中,不然很容易引起死結,

使用connect( )方法可以將這個管道搭建起來,再進行資料轉送~


這裡找了個簡單的小例子給大家體會下吧~


1)SendThread.java:(輸出資料流)

import java.io.IOException;import java.io.PipedOutputStream;public class SendThread extends Thread{private PipedOutputStream out = new PipedOutputStream();   public PipedOutputStream getOutputStream(){           return out;       }   public void run(){           String strInfo = "我是PipedOutputStream寫入的東西" ;           try {               out.write(strInfo.getBytes());               out.close();           } catch (IOException e) {               e.printStackTrace();           }       }   }

2)ReceiverThread.java:(輸入資料流)


import java.io.IOException;import java.io.PipedInputStream;public class ReceiverThread extends Thread {private PipedInputStream in = new PipedInputStream();public PipedInputStream getInputStream() {return in;}public void run() {byte[] buf = new byte[1024];try {int len = in.read(buf);System.out.println(new String(buf, 0, len));in.close();} catch (IOException e) {e.printStackTrace();}}}


測試類別:Test5.java:

import java.io.IOException;import java.io.PipedInputStream;import java.io.PipedOutputStream;public class Test5 {public static void main(String[] args) {ReceiverThread rThread = new ReceiverThread();SendThread sThread = new SendThread();// 擷取對應流:PipedOutputStream out = sThread.getOutputStream();PipedInputStream in = rThread.getInputStream();try {// 管道連結out.connect(in);sThread.start();rThread.start();} catch (IOException e) {e.printStackTrace();}}}


運行:





6)SequenceInputStream合并流:

見名知意,就是合并多個輸入資料流.即當我們需要從多個輸入資料流中向程式讀入資料的時候可以考慮使用合并流,

SequenceInputStream會將與之相串連的流集組合成一個輸入資料流並從第一個輸入資料流開始讀取,

直到到達檔案末尾,接著從第二個輸入資料流讀取,依次類推,直到到達包含的最後一個輸入資料流的檔案末尾為止;

合并流的作用是將多個源合并合一個源!


要注意的地方:(構造方法)

SequenceInputStream為我們提供了兩個不同的構造方法:

1~SequenceInputStream(Enumeration<? extends InputStream> e) 

2~SequenceInputStream(InputStream s1, InputStream s2)


PS:這個Enumertaion是一個介面,Enumeration介面定義了從一個資料結構得到連續資料的手段

該介面提供的兩個方法:

boolean hasMoreElements():測試此枚舉是否包含更多的元素。 

nextElement( ):如果此枚舉對象至少還有一個可提供的元素,則返回此枚舉的下一個元素.

這裡並不詳細介紹Enumertaion了,想瞭解的自行查閱文檔~




那麼接下來我們來寫兩個簡單的小程式方便我們理解:

①使用兩個流作為參數的構造方法:

public static void main(String[] args) throws IOException {          InputStream s1 = new ByteArrayInputStream("ABC".getBytes());          InputStream s2 = new ByteArrayInputStream("abc".getBytes());          InputStream in = new SequenceInputStream(s1, s2);          int data;          while ((data = in.read()) != -1) {              System.out.println(data);          }          in.close();      }  

運行結果:(對應ABCabc的ASCII碼值,別問我為什麼不用漢字,因為本節講的是位元組流,一個漢字兩個位元組~)




②使用Enumeration作為參數的那個構造方法:

public static void main(String[] args) throws IOException {  //建立合并流        SequenceInputStream sin = null;          //建立輸出資料流          BufferedOutputStream bout = null;          try {              //構建流集合              Vector<InputStream> vector = new Vector<InputStream>();              vector.addElement(new FileInputStream("D:\\test1.txt"));              vector.addElement(new FileInputStream("D:\\test2.txt"));              vector.addElement(new FileInputStream("D:\\test3.txt"));              vector.addElement(new FileInputStream("D:\\test4.txt"));              Enumeration<InputStream> e = vector.elements();                            sin = new SequenceInputStream(e);              bout = new BufferedOutputStream(                      new FileOutputStream("D:\\textUnion.txt"));                          //讀寫資料              byte[] buf = new byte[1024];              int len = 0;              while ((len = sin.read(buf)) != -1) {                  bout.write(buf, 0, len);                  bout.flush();              }          } catch (FileNotFoundException e1) {              e1.printStackTrace();          } catch (IOException e1) {              e1.printStackTrace();          } finally {              try {                  if (sin != null)                      sin.close();              } catch (IOException e) {                  e.printStackTrace();              }              try {                  if (bout != null)                      bout.close();              } catch (IOException e) {                  e.printStackTrace();              }          }      }  

接著我們在D盤目錄下建立:test1,test2,test3,test4四個txt檔案,內容依次為:

逗A,逗B,逗C,逗D

運行:

會在D盤下生產testUnion.txt的檔案,開啟檔案後可以看到:









最後說兩句:

好的,關於Java IO中的基本位元組流就講到這裡了,現在我們來回顧下本節講解的東東:

①InputStream和OutputStream兩個父類的相關方法

②FileInputStream與FileOutputStream類檔案讀寫類的使用,加入了緩衝數組提高了讀寫效率~

③ByteArrayInputStream與ByteArrayOutputStream類位元組數組類,我們寫了個擷取網頁源碼的例子:

④ObjectInputStream與ObjectOutputStream類對象讀寫類,我們通過這兩個類可以很方便地完成

從對象到流,流到對象的轉化,另外要注意一點,這個對象所屬的類要繼承Serializable介面!

⑤PipedOutputStream與PipedInputStream類管道輸入輸出類,這兩個是用於線程間進行通訊的,

一般避免把這兩個寫到同一個線程中,不然很容易引起死結,本節只是給出一個簡單的應用例子,後續有

需要再進行深入研究~

⑥SequenceInputStream合并流,就是可以將多個輸入資料流合并成一個輸入資料流,有兩種構造形式:

分別是兩個輸入資料流,或者一個Enumeration參數,也很簡單,大家看懂例子即可~



那麼,關於本節的基本位元組流就到這裡,謝謝你的閱讀~

如果你覺得本文可以的話,可花1s點個贊,讓更多的朋友可以看到這篇文章~萬分感謝~





聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.