字節流流總結
InputStream(抽象類:表示所有字節輸入流的父類)
|-FileInputStream(主要用于圖像數據之類的原始字節流)
|-FilterInputStream(簡單的重寫InputStream方法)
|-BufferedInputStream(提供緩沖等功能)
|-PipedInputStream(主要用于多線程)
OutputStream(抽象類:表示所有字節輸出流的父類)
|-FileOutputStream(主要用于圖像數據之類的原始字節流)
|-FilterOutputStream(簡單的重寫OutputStream方法)
|-BufferedOutputStream(提供緩沖等功能)
|-PRintStream(打印各種數據值得表示形式)
|-PipedOutputStream(主要用于多線程)
1、關于BufferedInputStream和FileInputStream的區別
在FileInputStream里有一個說明是說此方法將阻塞,意思就是說在你讀一個文件輸入流的時候,當讀到某個位置的時候,如果做一些其他處理(比如說接受一部分字節做一些處理等等)這個時候輸入流在什么位置就是什么位置,不會繼續往下讀,而BufferedInputStream雖然也有一個read方法,但是從名字就可以看出,它帶有一個緩沖區,它是一個非阻塞的方法,在你讀到某個位置的時候,做一些處理的時候,輸入流可能還會繼續讀入字節,這樣就達到了緩沖的效果。
public class SS { public static void main(String[] args) throws Exception { File f = new File("d://大型數據庫文件.mdf"); FileInputStream fis = new FileInputStream(f); //如果下面的語句使用BufferedOutputStream來修飾則帶來更好的性能現。 FileOutputStream fos = new FileOutputStream("e://" + f.getName()); int length = 0; byte[] b = new byte[1024]; while((length = fis.read(b)) != -1) { fos.write(b, 0, length); } fos.close(); fis.close(); }}
2、管道流
當需要在兩個線程中讀寫數據的時候,由于線程的并發執行,讀寫的同步問題可能會發生困難,這時候可以使用管道,管道事實上是一個隊列。
管道是由系統維護的一個緩沖區,當然程序員也可以自己直接指定該緩沖區的大小(只需要設置管道流類中的PIPE_SIZE屬性的值)。當生產者生產出數據后,只需要將數據寫入管道中,消費者只需要從管道中讀取所需要的數據。利用管道的這種機制,可以將一個線程的輸出結果直接連接到另一個線程的輸入端口,實現兩者之間的數據直接傳送。
線程1線程2臨時文件管道
管道的連接:
方法之一是通過構造函數直接將某一個程序的輸出作為另一個程序的輸入,在定義對象時指明目標管道對象
PipedInputStream pInput=new PipedInputStream();
PipedOutputStream pOutput= new PipedOutputStream(pInput);
方法之二是利用雙方類中的任一個成員函數 connect()相連接
PipedInputStream pInput=new PipedInputStream();
PipedOutputStream pOutput= new PipedOutputStream();
pinput.connect(pOutput);
管道的輸入與輸出:
輸出管道對象調用write()成員函數輸出數據(即向管道的輸入端發送數據);而輸入管道對象調用read()成員函數可以讀起數據(即從輸出管道中獲得數據)。這主要是借助系統所提供的緩沖機制來實現的。
實例:java的管道的輸入與輸出
import java.io.*;
public class PipedIO //程序運行后將sendFile文件的內容拷貝到receiverFile文件中
{
public static void main(String args[])
{
try
{
//構造讀寫的管道流對象
PipedInputStream pis=new PipedInputStream();
PipedOutputStream pos=new PipedOutputStream();
//實現關聯
pos.connect(pis);
//構造兩個線程,并且啟動。
new Sender(pos,"c://text2.txt").start();
new Receiver(pis,"c://text3.txt").start();
}
catch(IOException e)
{
System.out.println("Pipe Error"+ e);
}
}
}
//線程發送
class Sender extends Thread
{
PipedOutputStream pos;
File file;
//構造方法
Sender(PipedOutputStream pos, String fileName)
{
this.pos=pos;
file=new File(fileName);
}
//線程運行方法
public void run()
{
try
{
//讀文件內容
FileInputStream fs=new FileInputStream(file);
int data;
while((data=fs.read())!=-1)
{
//寫入管道始端
pos.write(data);
}
pos.close();
}
catch(IOException e)
{
System.out.println("Sender Error" +e);
}
}
}
//線程讀
class Receiver extends Thread
{
PipedInputStream pis;
File file;
//構造方法
Receiver(PipedInputStream pis, String fileName)
{
this.pis=pis;
file=new File(fileName);
}
//線程運行
public void run()
{
try
{
//寫文件流對象
FileOutputStream fs=new FileOutputStream(file);
int data;
//從管道末端讀
while((data=pis.read())!=-1)
{
//寫入本地文件
fs.write(data);
}
pis.close();
}
catch(IOException e)
{
System.out.println("Receiver Error" +e);
}
}
}
3、PrintStream與PrintWriter
PrintStream在OutputStream基礎之上提供了增強的功能,即可以方便地輸出各種類型的數據(而不僅限于byte型)的格式化表示形式。PrintStream的方法從不拋出IOEceptin
PrintWriter提供了PrintStream的所有打印方法,其方法也從不拋出IOException。與PrintStream的區別:作為處理流使用時,PrintStream只能封裝OutputStream類型的字節流,而PrintWriter既可以封裝OutputStream類型的字節流,還能夠封裝Writer類型的字符輸出流并增強其功能。
classIODemo {
publicstaticvoidmain(String[]args) {
try{
FileReaderfr=newFileReader("a.txt");
BufferedReaderbr=newBufferedReader(fr);
FileWriterfw=newFileWriter("33.txt");
PrintWriterpw=newPrintWriter(fw);
Strings=br.readLine();
while(null!=s){
//PrintWriter的println方法相當于
//BufferedWriter的write()+newLine()
pw.println(s);
s=br.readLine();
}
br.close();
pw.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
}
如果將上面的PrintWriter換成PrintStream會報錯,因為PrintStream只能封裝字節流,不能封裝Writer類對象。
注:如果對輸出流的格式有特殊要求,使用PrintStream, PrintWriter顯然會比較方便
4、InputStream讀取數據問題
關于InputStream.read() 在從數據流里讀取數據時,為圖簡單,經常用InputStream.read()方法。這個方法是從流里每次只讀取讀取一個字節,效率會非常低。 更好的方法是用InputStream.read(byte[] b)或者InputStream.read(byte[] b,int off,int len)方法,一次讀取多個字節。
關于InputStream類的available()方法 要一次讀取多個字節時,經常用到InputStream.available()方法,這個方法可以在讀寫操作前先得知數據流里有多少個字節可以讀取。需要注意的是,如果這個方法用在從本地文件讀取數據時,一般不會遇到問題,但如果是用于網絡操作,就經常會遇到一些麻煩。比如,Socket通訊時,對方明明發來了1000個字節,但是自己的程序調用available()方法卻只得到900,或者100,甚至是0,感覺有點莫名其妙,怎么也找不到原因。其實,這是因為網絡通訊往往是間斷性的,一串字節往往分幾批進行發送。本地程序調用available()方法有時得到0,這可能是對方還沒有響應,也可能是對方已經響應了,但是數據還沒有送達本地。對方發送了1000個字節給你,也許分成3批到達,這你就要調用3次available()方法才能將數據總數全部得到。 如果這樣寫代碼:int count = in.available();byte[] b = new byte[count];in.read(b); 在進行網絡操作時往往出錯,因為你調用available()方法時,對發發送的數據可能還沒有到達,你得到的count是0。 需要改成這樣:int count = 0;while (count == 0) {count = in.available();}byte[] b = new byte[count];in.read(b);關于InputStream.read(byte[] b)和InputStream.read(byte[] b,int off,int len)這兩個方法都是用來從流里讀取多個字節的,有經驗的程序員就會發現,這兩個方法經常讀取不到自己想要讀取的個數的字節。比如第一個方法,程序員往往希望程序能讀取到b.length個字節,而實際情況是,系統往往讀取不了這么多。仔細閱讀Java的API說明就發現了,這個方法并不保證能讀取這么多個字節,它只能保證最多讀取這么多個字節(最少1個)。因此,如果要讓程序讀取count個字節,最好用以下代碼:byte[] b = new byte[count];int readCount = 0; // 已經成功讀取的字節的個數while (readCount < count) {readCount += in.read(bytes, readCount, count - readCount);} 用這段代碼可以保證讀取count個字節,除非中途遇到IO異常或者到了數據流的結尾(EOFException)
新聞熱點
疑難解答