java-17(2)-字符流缓冲区

1.缓冲区的出现是为了提高读写效率。
2.字符流缓冲区

BufferedWriter:
将文本写入字符输出流,缓冲各个字符,
从而提供单个字符、数组和字符串的高效写入。
特有方法:newline();//分行
BufferedReader:
从字符输入流中读取文本,缓冲各个字符,
从而实现字符、数组和行的高效读取。
特有方法:readLine();//读取一行数据,当下一行没有数据时返回null。
//利用缓冲区读写的基本操作
private static void demo1() throws IOException {
        //创建了一个输出流对象并关联了一个buf1.txt文件
        FileWriter fw = new FileWriter("buf1.txt");
        //为了提高写入的效率,创建了一个字符流的缓冲区,并和要缓冲的输出流对象产生关联。
        BufferedWriter bufw = new BufferedWriter(fw);

        for (int i = 0; i < 10; i++) {
            bufw.write("haha"+i);
            //分行符
            bufw.newLine();
            //利用缓冲区的刷新方法,将数据刷到目的地中。
            bufw.flush();
        }
        //关闭缓冲区实质上是关闭了流对象
        bufw.close();
    }


private static void demo2() throws IOException {
        //创建一个输入数据流对象
        FileReader fr = new FileReader("buf1.txt");
        //为了提高输入效率,创建缓冲区对象,并和指定要缓冲的输入流对象关联。
        BufferedReader bufr = new BufferedReader(fr);

        String line ;
        while ((line = bufr.readLine())!=null){
            System.out.println(line);
        }

        char[] buf = new char[1024];
        int len;
        while ((len = bufr.read(buf))!=-1){
            System.out.println(new String(buf,0,1024));
        }
        bufr.close();
    }

3.利用缓冲区实现文本的复制功能。

    private static void demo2() {
        FileReader fr = null;
        BufferedReader bufr = null;
        FileWriter fw = null;
        BufferedWriter bufw = null;
        try {
            fr = new FileReader("buf1.txt");
            bufr = new BufferedReader(fr);

            fw = new FileWriter("Copybuf1.txt");
            bufw = new BufferedWriter(fw);

            String line;
            while ((line = bufr.readLine())!=null){
                bufw.write(line);
                bufw.newLine();
                bufw.flush();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bufr != null){
                try {
                    bufr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

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

4.自定义读取缓冲区的实现,模拟一个BufferedReader.


/*
* 自定义的读取缓冲区,模拟一个BufferedReader.
*
* 分析:缓冲区无非就是封装了一个数组。
* 并对外提供了更多的方法对数组进行访问。
* 其实这些方法最终操作的都是数组的角标。
*
* 缓冲的原理:
* 其实就是从源中获取一批数据装进缓冲区。
* 再从缓冲区中不断的取出一个个数据。
*
* 在此次取完后,再从源中继续取一批数据进缓冲区,
* 当源中的数据取完时,用-1作为结束标记。
*
* */   
class MyBufferedReader extends Reader{
    //创建一个FileReader对象,接收构造函数接收的FileReader对象。
    //创建一个指针,对数组进行操作。当操作到最后一个元素后,指针应归零;

    private int pos = 0;
    //创建一个计数器,存储数组中元素的个数。取出一个元素就自减。当为0时就继续从硬盘中读取数据到数组。
    private int count = 0;
    //创建一个数组,作为缓冲区。
    private char[] buf = new char[1024];
    MyBufferedReader(Reader r){
        this.r = r;
    }

    private Reader r =null;

    //从硬盘中读取一个字符,存入数组,并返回其值
    public int MyRead() throws IOException {
        //1.从源中获取一批数据到缓冲区中。需要先做判断,只有计数器为0时,才需要从源中获取数据。
        if( count == 0 ){
            count = r.read(buf);//可以获取数组中存放的元素个数
            pos = 0;//每次获取数据到缓冲区后,角标置为0;
        }
        if (count<0){
            return -1;
        }
        char ch = buf[pos];
        pos++;
        count--;
        return ch;
    }
    public String MyReadLine() throws IOException {
        //创建一个行缓冲区
        StringBuilder sb = new StringBuilder();

        int ch = 0;

        while((ch = MyRead())!= -1){
    //当读到'\r'读到了行结束标志,跳过这一次不把ch存入到行缓冲区。
            if (ch=='\r'){
                continue;
            }
            if (ch=='\n'){
                return sb.toString();
            }
            //从缓冲区读到的字符,存储到缓存行数据的缓冲区。
            sb.append((char) ch);

        }
        if (sb.length() != 0 ){
            return sb.toString();
        }
        return null;
    }


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

    public void close() throws IOException {
        r.close();
    }
}

class MyLineNumberReader extends MyBufferedReader{
    private int LineNumber = 0;
    MyLineNumberReader(Reader r) {
        super(r);
    }

    public int getLineNumber() {
        return LineNumber;
    }

    public String MyReadLine() throws IOException {

        StringBuilder sb = new StringBuilder();

        int ch = 0;

        while((ch = MyRead())!= -1){

            if (ch=='\r'){
                continue;
            }
            if (ch=='\n'){
                LineNumber++;
                return sb.toString();
            }
            //从缓冲区读到的字符,存储到缓存行数据的缓冲区。
            sb.append((char) ch);

        }
        if (sb.length() != 0 ){
            LineNumber++;
            return sb.toString();
        }
        return null;
    }
}

5.装饰设计模式:

对一组对象的功能进行增强时,就可以使用该设计模式。

装饰和继承都可以实现一样的特点:功能的扩展增强。那么两者有什么区别呢?
下面就来举个列子:

首先有一个继承体系。
Writer
    TextWriter:用于操作文本。
    MediaWriter:用于操作媒体。
想要对操作的动作提高效率。按照面向对象,可以通过继承对具体的对象进行功能的扩展,效率的提高需要加入缓冲技术。
如下:
Writer
    TextWriter:用于操作文本
        BufferedTextWriter:加入了缓冲技术的操作文本的流对象。
    MediaWriter:用于操作媒体。
        BufferedMediaWriter:加入了缓冲技术的操作媒体的流对象。
这样做并不理想。
如果这个体系进行功能扩展,有多了几个流对象,那么这个流要提高效率,
是不是也要产生子类呢?是,这时就会发现只为提高功能,进行的继承,
导致继承体系越来越臃肿,不够灵活。


重新思考这个问题?
既然加入的都是同一种技术--缓冲。
前一种是让缓冲和具体的对象相结合。
可不可以将缓冲进行单独的封装,哪个对象需要缓冲就将对象和缓冲相关联。
class Buffer{
    Buffer(TextWriter w){

    }

    Buffer(MediaWriter w){

    }

class Buffer extends Writer{
    Buffer(Writer w){

    }
}
Writer
    TextWriter:用于操作文本。
    MediaWriter:用于操作媒体。
    BufferWriter:用于提高效率。
装饰类比继承更为灵活。
特点:装饰类和被装饰的类必须所属同一个接口或者父类。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值