Java 杂谈Java学习笔记

I/O输入/输出

2017-05-29  本文已影响46人  起个名忒难
引言

对程序语言设计者来说,设计一个令人满意的I/O(输入输出)系统,是件极艰巨的任务,摘自《Thinking in Java 》

概述

JAVA程序通过流来完成输入/输出。流是生产或消费信息的抽象,流通过Java的输入/输出系统与物理设备连接。JAVA的I/O通过java.io包下的类和接口来支持,主要是5个类和一个接口。

File类

一个File类的对象,表示了磁盘上的文件或目录,提供了与平台无关的方法来对磁盘上的文件或者目录进行操作,直接处理文件或目录,但是不能访问文件本身。

在java.io包中提供了60多了类流:

从功能上分为:

从流的角色上分为:

从流的结构上分为:

在最底层,所有的输入输出都是以字节为单位的,基于字符的流只是为处理字符提供方便有效的方法。它们的操作方式几乎完全一样,只是操作的数据单元不同,字节流操作的数据单元是字符,字符流操作的数据单元是字符。

类流全家福

I/O流类.png

从上面的图片中,可以看出无论是字节流和字符流都提供了对文件,数组,字符串,管道,对象,音频等内容的输入/输出流支持。

对输入/输出流基类的简单介绍

InputSteam 三个基本的读方法:
abstract int read(): 读取一个字节数据,并返回读到数据的末尾,如果返回-1 , 表示都到了输入流的末尾。

int read(byte[] b ): 将数据读入一个字节数组,同时返回实际读取的字节数,如果返回-1 ,表示读到了输入流的末尾。

int read(byte[] b , int off , int len):将数据读入一个字节数组,同时返回实际读取的字节数,如果返回-1 ,表示读到了输入流的末尾,off指定在数组b中存放数据的起始位置,len指定读取的最大字节数。

可能会有一个疑问,为什么上面的第一个方法是抽象,而其余两个read方法是具体的? 通过源码找到了想要的答案。第二个方法依靠了第三个方法,而第三个方法依靠了第一个方法实现,换句话说只有第一个read方法是与具体的I/O设备相关的,需要InputStream的子类来实现。源码如下:

public abstract int read() throws IOException;

public int read(byte b[]) throws IOException {
        return read(b, 0, b.length);  //调用第三个方法实现
    }

public int read(byte b[], int off, int len) throws IOException {
        //判断参数的合法性
        if (b == null) {
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }
        
        int c = read();   //调用第一个方法,读取一个字节
        if (c == -1) {
            return -1;   //没有字节返回-1 ,读取结束
        }
        b[off] = (byte)c;  //将读取到的字节放入数组中

        int i = 1;
        try {
            for (; i < len ; i++) {
                c = read();
                if (c == -1) {
                    break;
                }
                b[off + i] = (byte)c;  //将读取到的字节放入数组中,读取的长度大于数据长度,循环读取结束
            }
        } catch (IOException ee) {
        }
        return i;  //返回读取的字节数组长度
    }

其它方法
long skip(long n ):输入流中跳过n个字节,并返回实际跳过的字节数
void close():关闭流
。。。

OutputStream 主要方法
void write(byte[]] b ):将参数b中的字节写到输出流
void write(byte[] b , int off ,int len):将参数b的从偏移量off开始len个字节写到输出流
abstract viud write(int b ):先将int转换成byte类型,把低字节写入到输出流中
void flush():将缓冲区中的字节全部输出,并清空缓存区
void close():关闭输出流并释放与流相关的系统资源

Reader里包含的3个读取方法:
int read():
int read(char[] c):
int read(char[] c ,int off , int len) :

Write包含的方法
void write(char[] c)
void write(String str)
void write(String str, int off, int len)
abstract flush()
void close()

根据上面图片做一个简单的总结:

I/O流的链接示意图:

流的链接示意图.png

常用类
FileInputStream , FileOutputStream , ByteArrayInputStream, ByteArrayOutputStream ,BufferedReader,BufferedWriter, ,InputStreamReader ,InputStreamWriter,FileReader ,FileWriter

如何选择I/O流

确定是输入还是输出

输入:输入流 InputStream Reader
输出:输出流 OutputStream Writer

明确操作的数据对象是否是纯文本

是:字符流 Reader,Writer
否:字节流 InputStream,OutputStream

明确具体的设备。

文件:
读:FileInputStream,, FileReader,
写:FileOutputStream,FileWriter

数组:
byte[ ]:ByteArrayInputStream, ByteArrayOutputStream
char[ ]:CharArrayReader, CharArrayWriter

String:
StringBufferInputStream(已过时,因为其只能用于String的每个字符都是8位的字符串), StringReader, StringWriter

Socket流
键盘:用System.in(是一个InputStream对象)读取,用System.out(是一个OutoutStream对象)打印

是否需要转换流

是,就使用转换流,从Stream转化为Reader、Writer:InputStreamReader,OutputStreamWriter

是否需要缓冲提高效率

是就加上Buffered:BufferedInputStream, BufferedOuputStream, BufferedReader, BufferedWrite


少年听雨歌楼上,红烛昏罗帐。  
壮年听雨客舟中,江阔云低,断雁叫西风。
感谢支持!
                                        ---起个名忒难

上一篇下一篇

猜你喜欢

热点阅读