Java IO(2)—缓冲字符流以及IO中的装饰者模式

简介: 详细介绍了Java IO中的缓冲字符流BufferedWriter、BufferedReader、LineNumberReader的使用方式,以及Java IO中的装饰者模式。

1 BufferedWriter缓冲区字符输出流
public class BufferedWriter
extends Writer

特点:

自带缓冲区。缓冲区可以实现自动扩容,提高了写的效率。
特有的newLine(); 方法可以写入一个行分隔符。行分隔符字符串由系统属性 line.separator 定义,并且不一定是单个新行 ('\n') 符,可以实现跨平台。

1.1 构造器

创建一个使用默认大小输出缓冲区的缓冲字符输出流。Writer类,是一个抽象类,应该传递的是该抽象类的实现类对象。

创建一个使用给定大小输出缓冲区的新缓冲字符输出流。在大多数情况下,默认值就足够大了,因此该构造器一般不用。sz:输出缓冲区的大小,是一个正整数

为什么要传递一个流对象而不传递file或者路径呢?

因为缓冲区流仅仅多提供一个缓冲区的功能,是为了高效而设计的。真正的读写还是靠基本的流对象的方法实现!(即装饰设计模式)。并且关闭外层流就相当于关闭了内层的流!

1.2 API方法
大多数方法均继承或重写自直接父类Writer。

特有的方法:

写入一个行分隔符,即提供了一个换行的方法。

2 BufferedReader缓冲区字符输入流
public class BufferedReader
extends Reader
特点:

自带缓冲区。可以实现自动扩容,提高了读的效率。
提供了readLine方法,一次可以读取一行数据。
2.1 构造器

创建一个使用默认大小输入缓冲区的缓冲字符输入流。传递一个实现Reade实现类。

2.2 API方法
大部分方法都继承和重写自父类Reader。

特有的方法:

能够一个读取一行数据,提高了读的效率。返回包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回null。

2.2.1 readLine方法实现原理
BufferedReader构造的时候,包装了一个类:FileReader。

其底层是调用了FileReader#read()方法,一次读取一个字符,将读取的字符放在缓冲区,当读取到换行符号的时候,将一行数据返回到内存当中,“\r’的ASCII码为13,“\n”的ASCII码为10。

3 案例
3.1 写入文件
/**

  • @author lx

*/
public class BufferedWriterDemo01 {

public static void main(String[] args) {
    BufferedWriter bw = null;
    try {
        bw = new BufferedWriter(new FileWriter("C:\\Users\\lx\\Desktop\\test.txt"));
        bw.write(97);
        bw.newLine();
        bw.write("nishuo");
        bw.newLine();
        bw.write("你说啥你", 1, 2);
        bw.newLine();
        char[] ch = new char[]{'1', '-', '\t', ' '};
        bw.write(ch);
        bw.write(ch, 1, 2);
        bw.flush();

    } catch (IOException e) {
        e.printStackTrace();
    } finally {

        if (bw != null) {
            try {
                bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

}
3.2 读取文件
/**

  • @author lx

*/
public class BufferedReaderDemo01 {

public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader("C:\\Users\\lx\\Desktop\\test.txt"));
    String str;
    //一次读取一行
    while ((str = br.readLine()) != null) {
        System.out.println(str);
    }
    br.close();
}

}
3.3 拷贝文件
使用带有缓冲区的流,实现文件的copy。

/**

  • @author lx

*/
public class CopyFile {

public static void main(String[] args) {
    BufferedReader br = null;
    BufferedWriter bw = null;
    try {
        br = new BufferedReader(new FileReader("C:\\Users\\lx\\Desktop\\test.txt"));
        bw = new BufferedWriter(new FileWriter("C:\\Users\\lx\\Desktop\\test2.txt"));
        String str;
        //读取  写入
        while ((str = br.readLine()) != null) {
            bw.write(str);
            bw.newLine();
            bw.flush();
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (br != null) {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (bw != null) {
            try {
                bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

}
4 LinenumberReader跟踪行号缓冲字符输入流
public class LineNumberReader
extends BufferedReader
这是Reader的又一个包装类,其特点是:

是BufferedReader子类,具备缓冲区,具有有一次读取一行的方法。
具有获得行号和设置行号的方法
setLineNumber(int num); 设置行号
getLineNumber(); 获得当前行的行号,返回的是int 类型的值
注意:循环之前设置行号后,循环后获得第一行字符串行号是设置的行号+1。

构造器:

5 装饰设计模式
作用:对某个类的某个方法进行功能性的增强。

装饰模式的实现步骤:

定义一个类:装饰类。实现被装饰类的最上层的接口或类,让装饰类和被装饰类有共同的行为,即同一体系。
引入一个被装饰类,作为全局变量。这里选择reader抽象类,此后reader的子类都能使用。
将被装饰的类作为参数传递给装饰类的构造器,用于初始化变量。
对该被装饰类的某个方法进行功能性的增强。
5.1 Java IO中的装饰模式
BufferedReader类对Reader类的read()方法进行包装,它是基于read方法,并对read方法进行了功能的增强,形成readLine()方法。实际上整个IO流系统用的最多的就是装饰设计模式。

LineNumberReader类对BufferedReader类的readLine()方法进行包装,让其在调用时能够对行号计数,添加了获得行号和设置行号的方法。

5.2 装饰设计模式和继承的异同点
相同点:装饰设计模式和继承都是为了对某个类的行为或者属性的扩展(增强)。

不同点:

当我有2个功能差不多 但是操作数据对象不一样的功能的子类 想要扩展一样的功能的时候,继承需要给每个子类进行扩展,并且需要继承每一个方法,而装饰设计模式,只要写一份,把父类传进来就扩展了制定的方法。

这样如果为了某个功能的扩展而使用继承那么可能产生很多子类,那系统体系是非常臃肿的,并且继承的类之间耦合度高,不利于扩展。

装饰模式使用对象的依赖关系代替继承关系,允许系统动态决定“贴上”一个需要的“装饰”,或者除掉一个不需要的“装饰”。继承关系则不同,继承关系是静态的,它在系统运行前就决定了。因此装饰设计模式更加灵活,同时避免类型体系的快速膨胀降低了类与类之间的关系(即所谓的耦合性,继承的一个缺点就是耦合性太强)。

装饰模式符合程序设计开闭原则就是说对扩展开放,对修改关闭。在对某个类需要进行拓展的时候,最好不要修改原有的代码,而是要扩展原有代码,使用装饰设计模式就可以做到,使程序的扩展性好,易于维护和升级。

建议:通常使用装饰设计模式,少用继承。

5.3 案例
5.3.1 自定义读取一行的方法
自定义MyBufferedReader类:对FileReader类进行了包装并对FileReader 的read()方法进行功能性的增强,完成readLine方法的效果。

/**

  • @author lx

*/
public class MyBufferedReader extends Reader {

private Reader reader;

public MyBufferedReader(Reader reader) {
    this.reader = reader;
}

public String MyReaderLine() throws IOException {
    int read;
    StringBuilder sb = new StringBuilder();

    while ((read = reader.read()) != -1) {
        //判断是否等于13,13是\r的Unicode码,即回车符,回车符不加
        if (read == 13) {
            continue;
        }
        //判断是否是换行符,是换行就返回,不加,否则就添加
        if (read == 10) {
            return sb.toString();
        } else {
            sb.append((char) read);
        }
    }
    //到这说明读到了末尾,但是末尾可能没有\n,因此这里需要额外判断
    if (sb.length() > 0) {
        return sb.toString();
    }
    //走到这里说明,读到了末尾.并且缓冲数组的内容已经全部返回,读取完毕
    return null;
}

@Override
public int read(char[] cbuf, int off, int len) throws IOException {
    return reader.read(cbuf, off, len);
}

@Override
public void close() throws IOException {
    reader.close();
}

}
5.3.2 自定义设置和获得行号的方法
自定义MyLineNumberReader类,使用装饰设计模式,设计设置和获得行号并且读取一行的方法。

/**

  • @author lx

*/
public class MyLineNumberReader extends Reader {


private Reader reader;
private int num;

public MyLineNumberReader(Reader reader) {
    this.reader = reader;
}

public void setMyLineNumber(int num) {
    this.num = num;
}

public int getLineNumber() {
    return num;
}

public String myReadLine() throws IOException {
    StringBuilder sb = new StringBuilder();
    int read;
    while ((read = reader.read()) != -1) {
        if (read == '\r') {
            continue;
        }
        if (read == '\n') {
            num++;
            return sb.toString();
        } else {
            sb.append((char) read);
        }
    }
    if (sb.length() > 0) {
        num++;
        return sb.toString();
    }
    return null;
}

@Override
public int read(char[] cbuf, int off, int len) throws IOException {
    return reader.read(cbuf, off, len);
}

@Override
public void close() throws IOException {
    reader.close();
}

}

作者:刘Java
链接:https://juejin.cn/post/7002042608205692958
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

相关文章
|
5月前
|
监控 Java API
现代 Java IO 高性能实践从原理到落地的高效实现路径与实战指南
本文深入解析现代Java高性能IO实践,涵盖异步非阻塞IO、操作系统优化、大文件处理、响应式网络编程与数据库访问,结合Netty、Reactor等技术落地高并发应用,助力构建高效可扩展的IO系统。
180 0
|
2月前
|
Java Unix Go
【Java】(8)Stream流、文件File相关操作,IO的含义与运用
Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中。!但本节讲述最基本的和流与 I/O 相关的功能。我们将通过一个个例子来学习这些功能。
203 1
|
4月前
|
Java 测试技术 API
Java IO流(二):文件操作与NIO入门
本文详解Java NIO与传统IO的区别与优势,涵盖Path、Files类、Channel、Buffer、Selector等核心概念,深入讲解文件操作、目录遍历、NIO实战及性能优化技巧,适合处理大文件与高并发场景,助力高效IO编程与面试准备。
|
4月前
|
SQL Java 数据库连接
Java IO流(一):字节流与字符流基础
本文全面解析Java IO流,涵盖字节流、字符流及其使用场景,帮助开发者理解IO流分类与用途,掌握文件读写、编码转换、异常处理等核心技术,通过实战案例提升IO编程能力。
|
5月前
|
存储 Java Linux
操作系统层面视角下 Java IO 的演进路径及核心技术变革解析
本文从操作系统层面深入解析Java IO的演进历程,涵盖BIO、NIO、多路复用器及Netty等核心技术。分析各阶段IO模型的原理、优缺点及系统调用机制,探讨Java如何通过底层优化提升并发性能与数据处理效率,全面呈现IO技术的变革路径与发展趋势。
133 2
|
9月前
|
存储 网络协议 安全
Java网络编程,多线程,IO流综合小项目一一ChatBoxes
**项目介绍**:本项目实现了一个基于TCP协议的C/S架构控制台聊天室,支持局域网内多客户端同时聊天。用户需注册并登录,用户名唯一,密码格式为字母开头加纯数字。登录后可实时聊天,服务端负责验证用户信息并转发消息。 **项目亮点**: - **C/S架构**:客户端与服务端通过TCP连接通信。 - **多线程**:采用多线程处理多个客户端的并发请求,确保实时交互。 - **IO流**:使用BufferedReader和BufferedWriter进行数据传输,确保高效稳定的通信。 - **线程安全**:通过同步代码块和锁机制保证共享数据的安全性。
402 23
|
9月前
|
设计模式 Java 数据安全/隐私保护
Java 设计模式:装饰者模式(Decorator Pattern)
装饰者模式属于结构型设计模式,允许通过动态包装对象的方式为对象添加新功能,提供比继承更灵活的扩展方式。该模式通过组合替代继承,遵循开闭原则(对扩展开放,对修改关闭)。
|
Java
Java 中 IO 流的分类详解
【10月更文挑战第10天】不同类型的 IO 流具有不同的特点和适用场景,我们可以根据具体的需求选择合适的流来进行数据的输入和输出操作。在实际应用中,还可以通过组合使用多种流来实现更复杂的功能。
430 57
|
10月前
|
缓存 网络协议 Java
JAVA网络IO之NIO/BIO
本文介绍了Java网络编程的基础与历史演进,重点阐述了IO和Socket的概念。Java的IO分为设备和接口两部分,通过流、字节、字符等方式实现与外部的交互。
342 0
|
Java
java 中 IO 流
Java中的IO流是用于处理输入输出操作的机制,主要包括字节流和字符流两大类。字节流以8位字节为单位处理数据,如FileInputStream和FileOutputStream;字符流以16位Unicode字符为单位,如FileReader和FileWriter。这些流提供了读写文件、网络传输等基本功能。
234 10