Java IO笔记(Reader/Writer)


(最近刚来到简书平台,以前在CSDN上写的一些东西,也在逐渐的移到这儿来,有些篇幅是很早的时候写下的,因此可能会看到一些内容杂乱的文章,对此深感抱歉,以下为正文)


正文

本篇讲述的是Java IO中的Reader类和Writer类。跟之前讲述的InputStream和OutputStream一样为IO流中的抽象父类之一,不过Reader和Writer的操作对象不再是字节而是字符了。下面也不多说,贴上源码来加深我们的理解。

Reader.java

package java.io;
 
public abstract class Reader implements Readable, Closeable {
 
    /**
     * 声明一个Object对象,为后续方法进行同步操作时,提供同步锁
     */
    protected Object lock;
 
    /**
     * 一个不带参的构造方法,并将锁对象lock初始化为当前类
     */
    protected Reader() {
        this.lock = this;
    }
 
    /**
     *一个带一个参数的构造方法,传入一个Object对象,对传入参数进行安全监测后,将传入参数赋值给锁对象lock
     */
    protected Reader(Object lock) {
        if (lock == null) {
            throw new NullPointerException();
        }
        this.lock = lock;
    }
 
    /**
     * 一个带一个参数的read方法,传入的参数为一个字符缓冲区对象,从流中读取字符数据放置与字符缓冲区中,最终返回实际存储到字符缓冲区的字符的数量
     */
    public int read(java.nio.CharBuffer target) throws IOException {
    //返回字符缓冲区中可以使用的元素数量,将其作为临时字符数组的长度
        int len = target.remaining();
    //创建一个字符数组,用于读取流中的数据
        char[] cbuf = new char[len];
        int n = read(cbuf, 0, len);
    //读取数据后,将字符数组中的数据全部置于字符缓冲区中
        if (n > 0)
            target.put(cbuf, 0, n);
        return n;
    }
 
    /**
     *一个不带参数的read方法,每次读取一个字符,如果没有成功读取到字符数据返回-1,否则返回读取到的字符
     */
    public int read() throws IOException {
        char cb[] = new char[1];
        if (read(cb, 0, 1) == -1)
            return -1;
        else
            return cb[0];
    }
 
    /**
     * 一个带一个参数的read方法,传入的参数为一个字符数组,从流中读取数据,并将数据存放入传入的字符数组中,最终返回成功读取到的字符数量
     */
    public int read(char cbuf[]) throws IOException {
        return read(cbuf, 0, cbuf.length);
    }
 
    /**
     *一个带三个参数的read方法,该方法为抽象方法,第一个参数为一个字符数组,第二个参数为数据存储开始的位置,第三个参数为数据存储使用的长度
     */
    abstract public int read(char cbuf[], int off, int len) throws IOException;
 
    /**
     *声明了一个静态常量,maxSkipBufferSize,将其赋值为8192,该值表明了最多能跳过的字符数
     */
    private static final int maxSkipBufferSize = 8192;
 
    /** 
     *声明了一个字符数组,该数组用于跳过阅读
     */
    private char skipBuffer[] = null;
 
    /**
     * 一个带一个参数的skip方法,参数为long型,表明要跳过的长度
     */
    public long skip(long n) throws IOException {
    //对传入参数进行安全监测,如果小于0,则抛出异常
        if (n < 0L)
            throw new IllegalArgumentException("skip value is negative");
    //确定跳过的字符数量,如果n没有超过最大限定的值,则跳过n个长度,如果大于最大值,则跳过最大值的长度(maxSkipBufferSize)
        int nn = (int) Math.min(n, maxSkipBufferSize);
    //如果skipbuffer为空或者其容量不足以满足跳跃的长度,则新建一个skipBuffer
        synchronized (lock) {
            if ((skipBuffer == null) || (skipBuffer.length < nn))
                skipBuffer = new char[nn];
            long r = n;
    //根据需要跳过的长度来进行读取,最终返回实际跳过的字符数量
            while (r > 0) {
                int nc = read(skipBuffer, 0, (int)Math.min(r, nn));
                if (nc == -1)
                    break;
                r -= nc;
            }
            return n - r;
        }
    }
 
    /**
     * 检测当前流是否可读,此处永远返回false
     */
    public boolean ready() throws IOException {
        return false;
    }
 
    /**
     * 检测当前流是否支持标记功能,此处永远返回false
     */
    public boolean markSupported() {
        return false;
    }
 
    /**
     *一个带一个参数的mark方法,传入的参数为标记的位置,用于在流中进行标记,一般与reset方法一起使用
     */
    public void mark(int readAheadLimit) throws IOException {
        throw new IOException("mark() not supported");
    }
 
    /**
     *一个不带参数的reset方法,将流的读取位置重置到被mark方法标记的位置
     */
    public void reset() throws IOException {
        throw new IOException("reset() not supported");
    }
 
    /**
     * close方法用于关闭流,是一个抽象方法
     */
     abstract public void close() throws IOException;
 
}

Writer.java

package java.io;
 
public abstract class Writer implements Appendable, Closeable, Flushable {
 
    /**
     * 声明了一个字符数组,用于存放需要写出的数据
     */
    private char[] writeBuffer;
 
    /**
     * 定义了静态常量值 WRITE_BUFFER_SIZE,该值为存放写出数据的字符数组的初始容量,初始容量为1024
     */
    private static final int WRITE_BUFFER_SIZE = 1024;
 
    /**
     * 声明一个Object对象,为后续方法进行同步操作时,提供同步锁
     */
    protected Object lock;
 
    /**
     * 一个不带参的构造方法,并将锁对象lock初始化为当前类
     */
    protected Writer() {
        this.lock = this;
    }
 
    /**
     * 一个带有一个参数的Writer对象,传入的参数为一个Object对象,并将该值赋值给锁对象lock
     */
    protected Writer(Object lock) {
        if (lock == null) {
            throw new NullPointerException();
        }
        this.lock = lock;
    }
 
    /**
     * 带有一个参数的write方法,传入的是一个字符的int型值,每次写出一个字符
     */
    public void write(int c) throws IOException {
        synchronized (lock) {
            if (writeBuffer == null){
                writeBuffer = new char[WRITE_BUFFER_SIZE];
            }
            writeBuffer[0] = (char) c;
            write(writeBuffer, 0, 1);
        }
    }
 
    /**
     * 带有一个参数的write方法,传入的是一个字符型数组,将传入的数组中的内容一次写出
     */
    public void write(char cbuf[]) throws IOException {
        write(cbuf, 0, cbuf.length);
    }
 
    /**
     * 一个带有三个参数的write方法,第一个参数为一个字符型数组,其中存放着需要写出的数据,第二个参数为开始写出的位置,第三个参数为需要写出的长度
     *该方法为抽象方法
     */
    abstract public void write(char cbuf[], int off, int len) throws IOException;
 
    /**
     * 一个带有一个参数的write方法,该参数为一个要写出的字符串数据
     */
    public void write(String str) throws IOException {
        write(str, 0, str.length());
    }
 
    /**
     * 一个带有三个参数的write方法,第一个参数为要写出的字符串数据,第二个参数为开始写出的位置,第三个参数为需要写出的长度
     */
    public void write(String str, int off, int len) throws IOException {
        synchronized (lock) {
    //声明了一个字符数组
            char cbuf[];
    //如果writeBuffer没有创建过,则创建。如果写出长度<小于定义的初始容量,则wirteBuffer初始化容量为1024,如果大于,则用长度初始化其容量
            if (len <= WRITE_BUFFER_SIZE) {
                if (writeBuffer == null) {
                    writeBuffer = new char[WRITE_BUFFER_SIZE];
                }
                cbuf = writeBuffer;
            } else {    // Don't permanently allocate very large buffers.
                cbuf = new char[len];
            }
    //将需要写出的字符串转化为字符数组,写出
            str.getChars(off, (off + len), cbuf, 0);
            write(cbuf, 0, len);
        }
    }
 
    /**
     *一个带有一个参数的append方法,传入的参数为一个CharSequence类型的数据,经过安全监测后,将其转化为String型写出,最终返回当前Writer对象
     */
    public Writer append(CharSequence csq) throws IOException {
        if (csq == null)
            write("null");
        else
            write(csq.toString());
        return this;
    }
 
    /**
     * 一个带有三个参数的append方法,第一个参数是一个CharSequence类型的数据,第二个参数为要开始添加的位置,第三个参数为结束的位置
     */
    public Writer append(CharSequence csq, int start, int end) throws IOException {
    //对传入的csq先进行安全监测,通过后,根据起始位置和结束位置截取CharSequence数据,然后写出,最终返回当前Writer对象
        CharSequence cs = (csq == null ? "null" : csq);
        write(cs.subSequence(start, end).toString());
        return this;
    }
 
    /**
     * 一个带有一个参数的append方法,传入的参数为一个char型的数据,写入一个字符,最终返回当前Writer对象
     */
    public Writer append(char c) throws IOException {
        write(c);
        return this;
    }
 
    /**
     *一个抽象方法flush,该方法用于将缓存中的写入数据写出值目的处
     */
    abstract public void flush() throws IOException;
 
    /**
     * 关闭流
     */
    abstract public void close() throws IOException;
 
}

经过上面的源码可以看出,Reader/Writer和InputStream/OutputStream是十分相似的。当然也有一定的区别,最本质的区别就是前者是对字符进行操作,后者是对字节进行操作。并且两者间有些同名方法关于是否是抽象化方法略有不同。

以上为本篇的内容。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容