美文网首页
Java IO 总结

Java IO 总结

作者: ObadiObada | 来源:发表于2017-12-25 15:04 被阅读0次

    Java IO 总结

    概述

    IO 即输入输出输出系统,常见的操作系统,需要面对的介质非常之多,常见的IO介质有:

    • 文件
    • 网络
    • 内存缓存
    • 标准输入输出
    • 线程通信

    JDK设计了一系列接口和类,使面向不同的介质的IO操作都可以通过类似的接口来实现,这类接口都源自同一个抽象概念**

    流的分类

    按照数据的流向可分为:

    • 输入流
    • 输出流

    注意:输入流输出流是一个相对的概念,一般的从程序角度来定义:如果数据从程序流向设备则是输出,反之则是输入。

    按照流的处理方式又可分为:

    • 字节流
    • 字符流

    综合来讲流,可以按照如下分类

    字节流 字符流
    输入流 InputStream Reader
    输出流 OutputStream Writter

    JDK类库

    JDK对流的设计采用了一种名为装饰器的设计模式。以输入流为例, 常见的输出流类的继承结构如下:

    InputStream UML 图

    图中 ByteArrayInputStreamStringBufferInputStreamFileInputStreamPipedInputStreamStringBufferInputStream 等类直用于从不同介质读取数据,被称为原始流。而 FilterInputStream 以及他的子类都有一个输入参数为InputStream的构造函数,用于包装原始流以增加跟多的功能,这些类被称为包装类

    对于 OutputStreamReaderWriter JDK也采用了类似的设计,这里不再赘述.

    常用的字符流和字节流,原始流和包装类整理如下:

    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

    经常使用的类

    文件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();
            }
        }
    }
    

    输出结果:

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

    为文件读写增加缓存

    将上面读写的代码修改为写入10000000次,并一次读取64个字节,观察下写入和读取的时间:

    • 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);
    

    输出结果如下:

    Write 10000000 strings to a file cost : 131039

    Read all content string cost : 49534

    对上述代码再做修改,使用 BufferedInputStreamBufferedOutputStream 来包装 FileOutputStreamFileOutputStream 代码如下:

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

    输出结果如下:
    Write 10000000 strings to a file cost : 3552

    Read all content string cost : 11093

    从测试结果看,不论是读写,速度都大大提升。

    内存IO

    介质为内存的IO常有的流有:StringBufferInputStream,ByteArrayInputStream,PipedInputStream 等,前几种比较简单,本章主要介绍下 PipedOutputStream 和 PipedInputStream。PipedInputStream 和 PipedOutputStream需要成对出现,用于一个线程向另外一个线程写数据,下面是一个例子:

    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();
        }
    }
    

    输出结果为:

    ReadCount : 11 content Hello World

    可以注意到,PipedOutputStream创建时构造函数传入了一个PipedInputStream,在实际使用的过程中,也可以先创建PipedOutputStream 在将其作为参数用于创建PipedInputStream。

    网络IO

    网络IO一般是通过 Socket 和 HTTP 相关的API进行,流在这个过程中通常是直接通过相关对象获得,以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服务器,并读取两行数据,写入一行数据,最终输出如下:

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

    reply2 is +OK Capability list follows

    相关文章

      网友评论

          本文标题:Java IO 总结

          本文链接:https://www.haomeiwen.com/subject/irplgxtx.html