Reader类的使用方法和技巧,你掌握了吗?

2023-11-21 11:33:09 浏览数 (1)


theme: healer-readable

highlight: a11y-dark


哈喽,各位小伙伴们,你们好呀,我是喵手。

  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。

  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。

小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!

前言

在Java开发中,常常需要读取文件或者网络流等数据源,Reader类提供了一种方便的方式去读取字符流。本文将介绍Java中Reader类的详细用法和应用场景。

摘要

Reader类是一个抽象类,是所有字符输入流的超类,提供了基本的读取字符流的方法。Reader类还提供了许多实用的子类,例如InputStreamReader和FileReader。它们可以读取字节流并将其转换为字符流。本文主要介绍Reader类的基本使用和源代码解析,并给出一些应用场景案例和优缺点分析。

Reader类

简介

Reader类是Java IO API中的一个重要组成部分,是一个抽象类,用于读取字符流。它提供了多种方法,可以方便地读取字符流。Reader类继承了java.lang.Object类,实现了Closeable和Readable接口,其中Closeable接口表示一个可关闭的资源,Readable接口表示可以读取的资源。

Reader类的主要作用是从外部数据源中读取字符流,并将其提供给应用程序。在读取字符流的过程中,Reader类提供了一些实用的方法,例如read()、skip()等,这些方法可以用于读取和跳过字符流中的数据。同时,Reader类还提供了一些高级的方法,例如mark()、reset()等,这些方法可以用于标记和重置读取位置。

源代码解析

Reader类的主要源代码如下:

代码语言:java复制
public abstract class Reader implements Readable, Closeable {
    //...
    public int read(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;
    }

    public int read() throws IOException {
        char[] cb = new char[1];
        if (read(cb, 0, 1) == -1) {
            return -1;
        }
        return cb[0];
    }

    public int read(char cbuf[], int off, int len) throws IOException {
        //...
    }

    public long skip(long n) throws IOException {
        //...
    }

    public boolean ready() throws IOException {
        //...
    }

    public boolean markSupported() {
        return false;
    }

    public void mark(int readAheadLimit) throws IOException {
        throw new IOException("mark() not supported");
    }

    public void reset() throws IOException {
        throw new IOException("mark() not supported");
    }

    public abstract void close() throws IOException;
    //...
}

可以看到,Reader类提供了一些基本的方法,例如read()、skip()等,它们被所有子类所继承。同时,Reader类也提供了一些高级的方法,例如mark()、reset()等,这些方法需要子类自己去实现。在具体实现时,子类还需要覆盖Reader类中的抽象方法,例如read(char[] cbuf, int off, int len)等。

该代码展示了Reader类的一些主要方法,它是一个抽象类,实现了ReadableCloseable接口。其中,Reader类的主要作用是从输入流中读取字符或者字符数组,并提供了一些方法来管理输入流。

  1. read(CharBuffer target)方法:该方法将字符读入到指定的字符缓冲区中,返回读入的字符数。它内部实现调用了read(char cbuf[], int off, int len)方法,将读取到的字符放入到指定的字符缓冲区中。
  2. read()方法:该方法从输入流中读取一个字符,返回读入的字符的ASCII码值。它内部实现是调用了read(char cbuf[], int off, int len)方法读取字符,并将读入的字符转换为对应的ASCII码值返回。
  3. read(char cbuf[], int off, int len)方法:该方法从输入流中读取字符到指定的字符数组中。其中,off表示字符数组的起始偏移量,len表示将要读取的字符数。该方法返回实际读取的字符数,如果已到达文件结尾,返回-1。
  4. skip(long n)方法:该方法从输入流中跳过n个字符,返回实际跳过的字符数。如果n小于或等于0,则不执行任何操作,直接返回0。
  5. ready()方法:该方法判断输入流是否可以读取,如果可以则返回true,否则返回false。
  6. markSupported()方法:该方法判断该输入流是否支持标记和重新定位操作。由于Reader类的实现不支持标记和重新定位操作,因此该方法返回false。
  7. mark(int readAheadLimit)reset()方法:这两个方法都会抛出IOException异常,因为Reader类的实现不支持标记和重新定位操作。
  8. close()方法:该方法关闭输入流并释放与其相关的所有资源,如果输入流已经关闭,则不执行任何操作。

  如下是部分源码截图:

在这里插入图片描述在这里插入图片描述

应用场景案例

  1. 从文件中读取数据
代码语言:java复制
try (Reader reader = new FileReader("file.txt")) {
    int data = reader.read();
    while (data != -1) {
        System.out.print((char) data);
        data = reader.read();
    }
} catch (IOException e) {
    e.printStackTrace();
}
  1. 从网络中读取数据
代码语言:java复制
try (Reader reader = new InputStreamReader(new URL("https://www.example.com").openStream())) {
    int data = reader.read();
    while (data != -1) {
        System.out.print((char) data);
        data = reader.read();
    }
} catch (IOException e) {
    e.printStackTrace();
}
  1. 从标准输入中读取数据
代码语言:java复制
try (Reader reader = new InputStreamReader(System.in)) {
    int data = reader.read();
    while (data != -1) {
        System.out.print((char) data);
        data = reader.read();
    }
} catch (IOException e) {
    e.printStackTrace();
}

优缺点分析

优点

  • Reader类提供了一种方便的方式去读取字符流。
  • Reader类提供了多种实用的方法,例如read()、skip()等,可以方便地读取和跳过字符流中的数据。
  • Reader类提供了一些高级的方法,例如mark()、reset()等,可以用于标记和重置读取位置。

缺点

  • Reader类不能直接读取字节流,需要使用它的子类或者转换流来实现。
  • Reader类的read()方法是阻塞的,如果数据源中没有更多的数据,程序将会处于阻塞状态。

类代码方法介绍

  1. read()方法
代码语言:java复制
public abstract int read() throws IOException;

该方法用于读取一个字符,返回值为字符的整数表示形式,如果到达文件末尾,则返回-1。

  1. read(char[] cbuf, int off, int len)方法
代码语言:java复制
public int read(char cbuf[], int off, int len) throws IOException

该方法从字符流中读取len个字符,并将其存储在cbuf数组中,起始位置为off。返回值为实际读取的字符数,如果到达文件末尾,则返回-1。

  1. skip(long n)方法
代码语言:java复制
public long skip(long n) throws IOException

该方法跳过n个字符,返回值为实际跳过的字符数。

  1. ready()方法
代码语言:java复制
public boolean ready() throws IOException;

该方法返回是否可以立即从该输入流中读取数据。

  1. markSupported()方法
代码语言:java复制
public boolean markSupported()

该方法返回是否支持标记操作。

  1. mark(int readAheadLimit)方法
代码语言:java复制
public void mark(int readAheadLimit) throws IOException

该方法将当前读取位置标记为readAheadLimit,可以使用reset()方法以后返回该位置。该方法需要子类自己去实现。

  1. reset()方法
代码语言:java复制
public void reset() throws IOException

该方法将读取位置重置为上一次调用mark()方法时的位置。该方法需要子类自己去实现。

  1. close()方法
代码语言:java复制
public abstract void close() throws IOException;

该方法关闭输入流并释放与之关联的所有系统资源。

测试用例

测试代码演示

Reader类的单元测试用例如下:

代码语言:java复制
package com.example.javase.se.classes;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;

/**
 * @Author ms
 * @Date 2023-11-04 18:32
 */
public class ReaderTest {

    public static void main(String[] args) {
        Reader reader = null;
        try {
            reader = new StringReader("Hello World!");
            StringBuilder result = new StringBuilder();
            int data = reader.read();
            while (data != -1) {
                result.append((char) data);
                data = reader.read();
            }

            reader.mark(3);
            char[] buffer = new char[5];
            reader.read(buffer, 0, 5);
            assert new String(buffer).equals("Hello");
            reader.reset();
            buffer = new char[7];
            reader.read(buffer, 0, 7);
            System.out.println("new String(buffer) : "   buffer);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

测试结果

  根据如上测试用例,本地测试结果如下,仅供参考,你们也可以自行修改测试用例或者添加更多的测试数据或测试方法,进行熟练学习以此加深理解。

在这里插入图片描述在这里插入图片描述

测试代码分析

  根据如上测试用例,在此我给大家进行深入详细的解读一下测试代码,以便于更多的同学能够理解并加深印象。

该代码演示了如何使用Java中的Reader类,主要包括以下内容:

  1. 创建一个StringReader对象,该对象将字符串“Hello World!”封装为一个Reader对象。
  2. 创建一个StringBuilder对象,逐个读取StringReader中的字符,并将其添加到StringBuilder对象中。
  3. 使用Reader类的mark()方法和reset()方法,实现标记和重置Reader对象位置的功能。
  4. 创建一个字符数组,使用Reader类的read()方法将部分字符读入该数组中,并将其转换为字符串。
  5. 最后,关闭Reader对象。

总之,该代码演示了如何使用Java中的Reader类读取字符流并进行基本操作,包括标记和重置流的位置以及选择性读取部分字符。

... ...

总结

本文介绍了Java中的字符流读取类——Reader类。作为一个抽象类,Reader类提供了多种方法,可以便捷地读取字符流。本文对Reader类的基本概念及其应用场景进行了介绍,并详细解析了其源代码。同时,本文也分析了Reader类的优缺点,提醒读者在使用时需要注意其阻塞问题和不能直接读取字节流等特性。最后,本文还提出了Reader类的单元测试用例。整体而言,掌握Reader类的基本用法对Java开发人员来说非常重要。

文末

好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。

... ...

学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!

wished for you successed !!!


⭐️若喜欢我,就请关注我叭。

⭐️若对您有用,就请点赞叭。

⭐️若有疑问,就请评论留言告诉我叭。

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

0 人点赞