Java IO 總結(jié)

Java IO 總結(jié)

概述

IO 即輸入輸出輸出系統(tǒng),常見(jiàn)的操作系統(tǒng),需要面對(duì)的介質(zhì)非常之多,常見(jiàn)的IO介質(zhì)有:

  • 文件
  • 網(wǎng)絡(luò)
  • 內(nèi)存緩存
  • 標(biāo)準(zhǔn)輸入輸出
  • 線程通信

JDK設(shè)計(jì)了一系列接口和類(lèi),使面向不同的介質(zhì)的IO操作都可以通過(guò)類(lèi)似的接口來(lái)實(shí)現(xiàn),這類(lèi)接口都源自同一個(gè)抽象概念**

流的分類(lèi)

按照數(shù)據(jù)的流向可分為:

  • 輸入流
  • 輸出流

注意:輸入流輸出流是一個(gè)相對(duì)的概念,一般的從程序角度來(lái)定義:如果數(shù)據(jù)從程序流向設(shè)備則是輸出,反之則是輸入。

按照流的處理方式又可分為:

  • 字節(jié)流
  • 字符流

綜合來(lái)講流,可以按照如下分類(lèi)

字節(jié)流 字符流
輸入流 InputStream Reader
輸出流 OutputStream Writter

JDK類(lèi)庫(kù)

JDK對(duì)流的設(shè)計(jì)采用了一種名為裝飾器的設(shè)計(jì)模式。以輸入流為例, 常見(jiàn)的輸出流類(lèi)的繼承結(jié)構(gòu)如下:

InputStream UML 圖

圖中 ByteArrayInputStream,StringBufferInputStream,FileInputStream,PipedInputStream,StringBufferInputStream 等類(lèi)直用于從不同介質(zhì)讀取數(shù)據(jù),被稱(chēng)為原始流。而 FilterInputStream 以及他的子類(lèi)都有一個(gè)輸入?yún)?shù)為InputStream的構(gòu)造函數(shù),用于包裝原始流以增加跟多的功能,這些類(lèi)被稱(chēng)為包裝類(lèi)。

對(duì)于 OutputStreamReader,Writer JDK也采用了類(lèi)似的設(shè)計(jì),這里不再贅述.

常用的字符流和字節(jié)流,原始流和包裝類(lèi)整理如下:

Stream Original Stream Wrapper
InputStream ByteArrayInputStream
StringBufferInputStream
FileInputStream
PipedInputStream
FilterInputStream
PushbackInputStream
LineNumberInputStream
BufferedInputStream
DataInputStream
OutputStream FileOutputStream
PipedOutputStream
ByteArrayOutputStream
FileOutputStream
BufferedOutputStream
DataOutputStream
Reader InputStreamReader
StringReader
CharArrayReader
PipedReader
FilterReader
PushbackReader
BufferedReader
LineNumberReader
Writter InputStreamWritter
StringWritter
CharArrayWritter
PipedWritter
FilterWritter
PushbackWritter
BufferedWritter
LineNumberWritter

經(jīng)常使用的類(lèi)

文件IO

private static final String FILE_NAME = "D:\\test.txt";
private static final String NONSENS_CONTENT = "Once opon a time ...";

private static void writeFile() {
    File file = new File(FILE_NAME);
    FileOutputStream fos = null;
    try {
        if (!file.exists()) {
            file.createNewFile();
        }

        fos = new FileOutputStream(file);
        fos.write(NONSENS_CONTENT.getBytes());
        fos.flush();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (fos != null) {
            try {
                fos.close();
            } catch (IOException e) {
            }
        }
    }
}

private static void readFile() {
    File file = new File(FILE_NAME);
    FileInputStream fis = null;
    try {
        fis = new FileInputStream(file);
        byte[] bytes = new byte[(int) file.length()];
        int readCount = fis.read(bytes);
        String content = new String(bytes);
        System.out.print("readFile count:" + readCount + " content:" + content);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

輸出結(jié)果:

readFile count:20 content:Once opon a time ...

為文件讀寫(xiě)增加緩存

將上面讀寫(xiě)的代碼修改為寫(xiě)入10000000次,并一次讀取64個(gè)字節(jié),觀察下寫(xiě)入和讀取的時(shí)間:

  • Write
long start = System.currentTimeMillis();
byte bytes[] = NONSENS_CONTENT.getBytes();
fos = new FileOutputStream(file);
for (int i = 0; i < 10000000; i++) {
    fos.write(bytes);
}
fos.flush();
long duration = System.currentTimeMillis() - start;
System.out.println("Write 10000000 strings to a file cost : " + duration);
  • Read
fis = new FileInputStream(file);
byte[] bytes = new byte[50];
long start = System.currentTimeMillis();
while (fis.available() > 0) {
    fis.read(bytes);
}
long duration = System.currentTimeMillis() - start;
System.out.println("Read all content string cost : " + duration);

輸出結(jié)果如下:

Write 10000000 strings to a file cost : 131039

Read all content string cost : 49534

對(duì)上述代碼再做修改,使用 BufferedInputStreamBufferedOutputStream 來(lái)包裝 FileOutputStreamFileOutputStream 代碼如下:

  • Write
fos = new FileOutputStream(file);
bos = new BufferedOutputStream(fos, 1024);
  • Read
fis = new FileInputStream(file);
bis = new BufferedInputStream(fis, 1024);

輸出結(jié)果如下:
Write 10000000 strings to a file cost : 3552

Read all content string cost : 11093

從測(cè)試結(jié)果看,不論是讀寫(xiě),速度都大大提升。

內(nèi)存IO

介質(zhì)為內(nèi)存的IO常有的流有:StringBufferInputStream,ByteArrayInputStream,PipedInputStream 等,前幾種比較簡(jiǎn)單,本章主要介紹下 PipedOutputStream 和 PipedInputStream。PipedInputStream 和 PipedOutputStream需要成對(duì)出現(xiàn),用于一個(gè)線程向另外一個(gè)線程寫(xiě)數(shù)據(jù),下面是一個(gè)例子:

private static class WriteThread extends Thread {
    PipedOutputStream mOut;

    public WriteThread(PipedOutputStream pos) {
        super();
        mOut = pos;
    }

    public void run() {
        try {
            mOut.write("Hello World".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

private static class ReadThread extends Thread {
    PipedInputStream mIn;

    ReadThread(PipedInputStream pis) {
        super();
        mIn = pis;
    }

    public void run() {
        try {
            byte[] bytes = new byte[1024];
            int readCount = mIn.read(bytes);
            System.out.println("ReadCount : " + readCount + " content "
                    + new String(bytes, 0, readCount));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public static void main(String[] args) {

    try {
        PipedInputStream pis = new PipedInputStream();
        PipedOutputStream pos = new PipedOutputStream(pis);
        WriteThread writeThread = new WriteThread(pos);
        ReadThread readThread = new ReadThread(pis);
        writeThread.start();
        readThread.start();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

輸出結(jié)果為:

ReadCount : 11 content Hello World

可以注意到,PipedOutputStream創(chuàng)建時(shí)構(gòu)造函數(shù)傳入了一個(gè)PipedInputStream,在實(shí)際使用的過(guò)程中,也可以先創(chuàng)建PipedOutputStream 在將其作為參數(shù)用于創(chuàng)建PipedInputStream。

網(wǎng)絡(luò)IO

網(wǎng)絡(luò)IO一般是通過(guò) Socket 和 HTTP 相關(guān)的API進(jìn)行,流在這個(gè)過(guò)程中通常是直接通過(guò)相關(guān)對(duì)象獲得,以Socket為例:

public static void main(String[] args) {

    Socket socket = new Socket();
    SocketAddress addr = new InetSocketAddress("pop3.163.com", 110);
    OutputStream out = null;
    InputStream in = null;
    try {
        socket.connect(addr);
        in = socket.getInputStream();
        String reply = readLine(in);
        System.out.println("reply is " + reply);
        out = socket.getOutputStream();
        writeLine(out, "CAPA");
        reply = readLine(in);
        System.out.println("reply2 is " + reply);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (in != null) {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        if (out != null) {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        try {
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

private static String readLine(InputStream in) throws IOException {
    int d;
    StringBuilder sb = new StringBuilder();
    while ((d = in.read()) != -1) {
        if (d == '\r') {
            continue;
        } else if (d == '\n') {
            break;
        } else {
            sb.append((char) d);
        }
    }
    return sb.toString();
}

private static void writeLine(OutputStream out, String content) throws IOException {
    if (content != null && content.length() > 0) {
        out.write(content.getBytes());
        out.write('\r');
        out.write('\n');
    }
}

上面的代碼鏈接了163的POP3服務(wù)器,并讀取兩行數(shù)據(jù),寫(xiě)入一行數(shù)據(jù),最終輸出如下:

reply is +OK Welcome to coremail Mail Pop3 Server (163coms[b62aaa251425b4be4eaec4ab4744cf47s])

reply2 is +OK Capability list follows

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home...
    光劍書(shū)架上的書(shū)閱讀 4,178評(píng)論 2 8
  • 一、輸入和輸出 編程語(yǔ)言的I/O類(lèi)庫(kù)中常使用流這個(gè)抽象概念,它代表任何有能力產(chǎn)出數(shù)據(jù)的數(shù)據(jù)源對(duì)象或者是有能力接收數(shù)...
    端木軒閱讀 719評(píng)論 0 0
  • Java中I/O操作主要是指使用Java進(jìn)行輸入,輸出操作. Java所有的I/O機(jī)制都是基于數(shù)據(jù)流進(jìn)行輸入輸出,...
    cmlong_閱讀 556評(píng)論 0 4
  • 一、按字節(jié)流讀取 抽象類(lèi)inputStream和outputStream兩個(gè)以及他們的子類(lèi) Fileinputst...
    木以行舟閱讀 440評(píng)論 0 0
  • 我們的相遇很奇妙,同是一個(gè)班卻偏偏在期考時(shí)的考場(chǎng)相識(shí)。也許這就是緣分吧! 考試結(jié)束后我們迎來(lái)了期望已久...
    忘戀心閱讀 566評(píng)論 0 0

友情鏈接更多精彩內(nèi)容