Java輸入輸出流

相關概念

流的概念:

流是一組有順序的,有起點和終點的字節集合,是對數據傳輸的總稱或抽象。即數據在兩設備間的傳輸稱爲流,流的本質是數據傳輸,根據數據傳輸特性將流抽象爲各類類,方便更直觀的進行數據操做。流的源端和目的端可簡單地當作是數據的生產者和消費者,對輸入流,可沒必要關心它的源端是什麼,只要簡單地從流中讀數據,而對輸出流,也可不知道它的目的端,只是簡單地往流中寫數據。java

流的劃分:

按照流向劃分數據流可分爲輸入流和輸出流。數組

輸入流:從磁盤,光盤,網絡,鍵盤輸入數據到內存。io包中的輸入流都繼承自InputStream或Reader。緩存

輸出流:從內存輸出數據到磁盤,磁帶,顯示器等地。io包中的輸出流都繼承自OutputStream或Writer。網絡

按照數據組織形式劃分數據流可分爲字節流和字符流。多線程

字節流:byte爲數據的最小單位。io包中的輸入流都繼承自InputStream或OutputStream。app

字符流:char爲數據的最小單位。io包中的輸入流都繼承自Reader或Writer。測試

按照功能劃分數據流可分爲低級流(節點流)和高級流(處理流)。this

低級流(節點流):節點流是能夠直接從/向一個特定的數據源(例如磁盤、內存、網絡)讀/寫數據的流。編碼

高級流(處理流):高級流不可直接從數據源讀/寫數據,而是鏈接在已存在的流(能夠是低級流或高級流)之上,爲流添加額外的擴展功能。spa

輸入輸出流整體劃分

字節流分類及其做用

字符流分類及其做用

通用API(黑體爲經常使用API)

OutputStream

public abstract void write(int b)              //向輸出流寫入單個字節

public void write(byte[] data)           //將字節數組data中數據寫入到輸出流中

public void write(byte[] data, int offset, int length)     //將字節數組data中「offset開始,共length長「的數據寫入到輸出流中

public void flush()        //刷新該輸出流,強制數據寫入到輸出流

void close()      //關閉輸出流並釋放與該流關聯的全部系統資源

InputStream

int available()      //能夠不受阻塞地今後輸入流讀取(或跳過)的估計字節數

void close()     //關閉此輸入流並釋放與該流關聯的全部系統資源

void mark(int readlimit)     //在此輸入流中標記當前的位置,若是讀取字節數超過readlimit,則不標記任何字節

boolean markSupported()     //測試此輸入流是否支持 mark 和 reset 方法

abstract int read()     //從輸入流中讀取數據的下一個字節

int read(byte[] b)     //從輸入流中讀取必定數量的字節,並將其存儲在字節數組 b 中

int read(byte[] b, int off, int len)     //將輸入流中從"off開始的最多 len字節數據"讀入 byte 數組

void reset()     //將此流從新定位到最後一次對此輸入流調用 mark 方法時的位置

long skip(long n)     //跳過和丟棄此輸入流中數據的 n 個字節

Reader

abstract  void  close()     //關閉該流並釋放與之關聯的全部資源

void  mark(int readAheadLimit)     //標記流中的當前位置

boolean  markSupported()     //判斷此流是否支持 mark() 操做

int  read()     //讀取單個字符

int  read(char[] cbuf)     //將字符讀入數組

abstract  int  read(char[] cbuf, int off, int len)     //將字符讀入數組的「offset開始,共length長」的部分

int  read(CharBuffer target)     //試圖將字符讀入指定的字符緩衝區

boolean  ready()     //判斷是否準備讀取此流

void  reset()     //將此流從新定位到最後一次對此輸入流調用 mark 方法時的位置

long  skip(long n)     //跳過個字符

Writer

Writer  append(char c)     //將單個字符添加到輸出流                追加模式

Writer  append(CharSequence csq)     //將指定字符序列添加到輸出

Writer  append(CharSequence csq, int start, int end)     //將指定字符序列的子序列添加到輸出流

abstract  void  close()     //關閉此流

abstract  void  flush()     //刷新該流的緩衝

void  write(char[] cbuf)     //寫入字符數組

abstract  void  write(char[] cbuf, int off, int len)     //寫入字符數組的某一部分

void  write(int c)     //寫入單個字符

void  write(String str)     //寫入字符串

void  write(String str, int off, int len)     //寫入字符串的某一部分

部分流的特色

ByteArrayOutputStream:寫入ByteArrayOutputStream的數據被寫入到一個byte數組,緩衝區會隨着數據的不斷寫入而自動增加;可以使用toByteArray()和toString()獲取數據;沒法關閉,調用close方法仍然能夠以後向該流寫入數據。(ByteArrayInputStream相似)

public static void main(String args[]) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream(1);  //緩衝區長度爲4
    baos.write("helloworld".getBytes());   //可寫入超過1字節數據
    byte b[] = baos.toByteArray();
    String str = baos.toString();     //toByteArray和toString方法
    baos.close();      //嘗試關閉
    baos.write("!".getBytes());  //仍可寫入
    baos.writeTo(System.out);    //寫到特定輸出流中
    //結果:helloworld!
}

FileoutputStream:用於向文件進行寫入操做,getFD方法可獲取文件描述符,getChannel方法可獲取文件通道。

FileOutputStream fos = new FileOutputStream("fa.txt");
FileChannel fc = fos.getChannel();
FileDescriptor fd = fos.getFD();

ObjectOutputStream:組合ObjectInputStream來進行對基本數據或者對象的持久存儲

PipedOutputStream:和PipedInputStream一塊兒使用,能實現多線程間的管道通訊

DataOutputStream:裝飾其餘的輸出流,容許應用程序以與機器無關方式向底層寫入基本Java數據類型。(DataInputStream相似效果)

DataOutputStream dos = new DataOutputStream(new ByteArrayOutputStream());
dos.writeDouble(3.14);   //寫入double類型
dos.writeBoolean(true);   //寫入布爾類型
dos.writeChar(97);   //寫入char類型

BufferedOutputStream:爲另外一個輸出流添加緩衝功能,BufferedInputStream相似效果。

PrintStream:裝飾其餘輸出流,爲其餘輸出流添加功能,方便的打印各類數據值。

ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
ps.format("%-3.2f",3.1415926);
baos.writeTo(System.out);
//結果:3.14

PushbackInputStream:容許從流中讀取數據,而後在須要時推回該流。

byte[] b = "heo".getBytes();
PushbackInputStream pis = new PushbackInputStream(newByteArrayInputStream(b),3); //回推緩存三字節
byte[] bb = new byte[5];
pis.read(bb,0,2);   //將b中數據he讀入輸入流中
pis.unread("ll".getBytes());   //將ll放入回推緩存
pis.read(bb,2,3);     //讀取回推緩存數據後再讀取b中數據
System.out.println(new String(bb));
//結果
//hello

OutputStreamWriter:從字符流到字節流的橋接,自動將要寫入流中的字符編碼成字節。

ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(baos,"utf-8");  //指定編碼
osw.write("Sakura\n");
osw.write("最好了");
osw.flush(); 
baos.writeTo(System.out);
//結果
//Sakura
//最好了

各類流的使用場景

一,數據輸入仍是輸出
1) 輸入:使用Reader、InputStream 類型的子類。
2) 輸出:使用Writer、OutputStream 類型的子類。

二,數據格式

1) 二進制格式:使用InputStream、OutputStream 及其全部帶 Stream結尾的子類。
2) 純文本格式:使用Reader、Writer 及其全部帶 Reader、Writer 的子類。

三,數據源

1) 文件:字節流使用FileInputStream和FileOutputStream;對於字符流使用FileReader和 FileWriter。
2) 字節數組:則使用ByteArrayInputStream和ByteArrayOutputStream。
3) 字符數組:則使用CharArrayReader和CharArrayWriter。
4) String對象:字節流使用StringBufferInputStream和StringBufferOuputStream;字符流使用StringReader和StringWriter。

6、特殊須要
1) 轉換流:InputStreamReader、OutputStreamWriter。
2) 對象輸入輸出:ObjectInputStream、ObjectOutputStream。
3) 線程間通訊:PipeInputStream、PipeOutputStream、PipeReader、PipeWriter。
4) 合併輸入:SequenceInputStream。
5) 格式化輸出,則使用PrintStream或PrintWriter。

6)更特殊的須要:PushbackInputStream、PushbackReader、LineNumberInputStream、LineNumberReader。

7、緩衝

字節流使用BufferedInputStream和BufferedOutputStream;字節流使用BufferedReader和BufferedWriter。

一個實例

複製文件夾的類

import java.io.*;

public class Test{
    public static void main(String[] args) {
        copyClass cc = new copyClass("src\\old","src\\new");
        try {
            long start = System.currentTimeMillis();
            cc.copyDir(cc.getSource(),cc.getDestination(),false);
            long end = System.currentTimeMillis();
            System.out.println(end-start);
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

class copyClass{
    private File source;
    private File destination;
    copyClass(String  source, String destination){
        this.source = new File(source);
        this.destination = new File(destination);
    }

    void copyContent(File source,File destination,boolean byByte) throws IOException {
        if(byByte){       //字節數組複製
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source));
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destination));
            byte[] b = new byte[1024];
            while (bis.available()!= 0){
                bis.read(b);
                bos.write(b);
                bos.flush();
            }
            bis.close();
            bos.close();
        }
        else {     //單個字節複製
            FileInputStream fis = new FileInputStream(source);
            FileOutputStream fos = new FileOutputStream(destination);
            while (fis.available()!=0){
                int i = fis.read();
                fos.write(i);
            }
            fis.close();
            fos.close();
        }
    }

    void copyDir(File source, File destination,boolean byBytes) throws IOException{
        if (!source.isDirectory()){  //是文件則複製其內容
            copyContent(source,destination,byBytes);
        }
        else {
            if (destination.mkdirs()){   //是文件夾則遞歸複製
                File[] fs = source.listFiles();
                for (int i = 0; i < fs.length; i++) {
                    String fileName = fs[i].getName();
                    File newDestination = new File(destination.getPath() + File.separator + fileName);
                    copyDir(fs[i], newDestination,byBytes);
                }
            }
            else {
                System.out.print("Creat dirs failed!");
            }
        }

    }
    
    public File getSource() {
        return source;
    }

    public void setSource(File source) {
        this.source = source;
    }

    public File getDestination() {
        return destination;
    }

    public void setDestination(File destination) {
        this.destination = destination;
    }
}

結果

//採用單個字節複製方法耗時
1317
//採用緩衝區字節數組複製方法耗時
52
//減小了超過95%的時間

相當重要的是:除非數據流很是小,不然都應該使用數組來進行流的處理,必要時可用BufferedInputStream或BufferedOutputStream或BufferedWriter/BufferedReader來進行緩衝處理。

相關文章
相關標籤/搜索