Java IO 总结

Java IO 总结

概述

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

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

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

流的分类

按照数据的流向可分为:

  • 输入流
  • 输出流

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

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

  • 字节流
  • 字符流

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

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

JDK类库

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

Java IO 总结_第1张图片
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 总结)