2019-03-04

高效缓冲流,转换流基础知识详解

  • 能够高效读写的缓冲流,能够转换编码的转换流,能够持久化存储对象的序列化流等等。

高效缓冲流

  • 字节缓冲流: BufferedInputStream , BufferedOutputStream
  • 字符缓冲流: BufferedReader , BufferedWriter
    缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO 次数,从而提高读写的效率。
read()方法原理:
  • 在调用read()方法时,封装的FileReader里的底层流read(char[])方法会从硬盘中的一部分数据存入到缓冲区(含有字符数组)里边。
  • 进而调用BufferedReader里的read()方法一个一个的读取字符.读取完字符数组中的数据之后,会重新获取数据到字符数组中。
readLine方法原理:

在调用readLine之时,底层会调用缓冲区中的read()方法,将读取到的字符存储到另外一个容器中,当读到行终止符时,就将临时容器中存储的数据转成字符串返回。

自定义缓冲区

package oneSelf_Steam;

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

/**
 * @author lx
 * @date 2019/3/9 - 15:45
 * 自定义一个字符缓冲区。
 * 用于缓冲字符数据,从而提高操作效率。
 * 并提供了更多操作缓冲区数据的方法。
 * 需要使用具体的流对象未完成数据的获取。
 */
public class MyBufferedReader {
    private Reader r;
    //定义一个数组角标
    private int index = 0;
    //定义一个字符数组作为缓冲区
    private char[] buf = new char[1024];
    //定义一个计数器
    private int count = 0;

    //创建流构造器
    public MyBufferedReader(Reader r) {
        this.r = r;
    }

    //关流
    public void close(Reader r) throws IOException {
        r.close();
    }

    //需要先通过流对象从底层设备上获取一定数据到缓冲区数组中,使用流对象read(char[]);
    public int read() throws IOException {
        if (count == 0) {
            //  需要从设备上获取一定数量的数据存储到缓冲区中,
            // 并用count记录存储字符的个数。
            count = r.read();
            //每获取一次底层来的数据,角标清零。
            index = 0;
        }//如果读取结束了,count<0.直接返回-1
        if (count < 0) {
            return -1;
        }
        //获取缓冲区的一个字符
        int ch = buf[index];
        //角标自增
        index++;
        //计数器自减
        count--;
        return ch;
    }

    /**
     * 思路:
     * 从缓冲区中读取一个字符,并将这个字符存储到临时容器中
     * 存储之前要进行判断,如果遇到行终止符,停止存储,
     * 直接将临时容器中的数据转成字符串返回
     *
     * @return
     */

    public String readLine() throws IOException {
        //定义一个临时容器  StringBuilder是线程安全的
        StringBuilder bu = new StringBuilder();
        /**
         *  调用本类中的read()方法,从缓冲区中读取一个字符,
         *  存储到临时容器中,存储前判断是否是行终止符
         */
        int ch = 0;
        while ((ch = r.read()) != -1) {
            if (ch == '\r') {
                continue;
            }
            if (ch == '\n') {
                return bu.toString();
            }
            bu.append((char) ch);
        }

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

自定义缓冲区测试类

package oneSelf_Steam;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;


public class MybufferDemo {
    public static void main(String[] args) throws IOException {
        MyBufferedReader mybufer=new MyBufferedReader(new FileReader("D:\\Java代码\\Java基础加强\\Day10_Add\\面向对象到日历类5天知识小结.txt"));

        String line=null;

        while ((line=mybufer.readLine())!=null){
            System.out.println(line);
        }
        mybufer.close();
    }
}

效率测试

  • 使用高效缓冲字节流一个字节一个字节的读取写入。
package bufferedStream;

import java.io.*;

/**
 * public BufferedInputStream(InputStream in) :创建一个新的缓冲输入流。
 * public BufferedOutputStream(OutputStream out) : 创建一个新的缓冲输出流
 */
public class BufferedDemo {
    public static void main(String[] args) throws IOException {
        //计算开始时间
        long first=System.currentTimeMillis();
        BufferedInputStream inputStream =null;
        BufferedOutputStream outputStream=null;
        // 创建字节缓冲输入流
        try {
          inputStream= new BufferedInputStream(new FileInputStream("D:\\Java代码\\Java基础加强\\Day10\\src\\bufferedStream\\枪.mp4"));

          // 创建字节缓冲输出流
            outputStream=new BufferedOutputStream(new FileOutputStream("D:\\Java代码\\Java基础加强\\Day10\\src\\copy.mp4"));
          int len;

            while ((len=inputStream.read())!=-1) {
                outputStream.write(len);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inputStream != null) inputStream.close();
        }
       long end=System.currentTimeMillis();

        System.out.println("使用高校缓冲区所消耗的时间是:"+(end-first)+"ms");
        //使用高校缓冲区所消耗的时间是:866ms
    }
}

** 使用普通字节流一个字节一个字节的读取写入**

package bufferedStream;

import java.io.*;

public class StreamDemo {
    public static void main(String[] args) {
        long begin=System.currentTimeMillis();

        FileInputStream in=null;
        FileOutputStream out=null;

        try {
            in=new FileInputStream("D:\\Java代码\\Java基础加强\\Day10\\src\\bufferedStream\\枪.mp4");
            out=new FileOutputStream("D:\\Java代码\\Java基础加强\\Day10\\src\\普通字节流复制.mp4");

            int len;
        while ((len=in.read())!=-1){
            out.write(len);
        }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (out == null) {
                try {
                    out.close();

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

        }
        long end=System.currentTimeMillis();

        System.out.println("使用普通字节流复制视频所需毫秒值为"+(end-begin));
        //使用普通字节流复制视频所需毫秒值为288631
        //  288631/1000/60=4.8分钟
        //实用高效缓冲区只需要886毫秒,也就是不到1秒的时间完成。
    }
}

** 使用字节数组,普通字节流来复制视频文件**

package bufferedStream_byteArray;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 创建输入输出流对象
 * 创建字节数组读取
 */
public class StreamDemo2_ByteArray {
    public static void main(String[] args) {
        long begin=System.currentTimeMillis();

        FileInputStream in=null;
        FileOutputStream out=null;
        try {
            in=new FileInputStream("D:\\Java代码\\Java基础加强\\Day10\\src\\bufferedStream\\枪.mp4");
            out=new FileOutputStream("D:\\Java代码\\Java基础加强\\Day10\\src\\普通字节流复制.mp4");

            int len;
            byte [] bytes=new byte[1024];
            while ((len=in.read(bytes))!=-1){

                out.write(bytes,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (out == null) {
                try {
                    out.close();

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

        }
        long end=System.currentTimeMillis();

        System.out.println("使用普通字节流,字节数组复制视频所需时间为:"+(end-begin)+"毫秒");

        //        使用普通字节流,字节数组复制视频所需时间为:507毫秒
            //明显快了不少

    }
}

使用高校缓冲区,字节数组测试

package bufferedStream_byteArray;

import java.io.*;

public class BufferedByteDemo {
    public static void main(String[] args) {
        //计算开始时间
        long first=System.currentTimeMillis();
        BufferedInputStream in =null;
        BufferedOutputStream out=null;
        // 创建字节缓冲输入流
        try {
            in= new BufferedInputStream(new FileInputStream("D:\\Java代码\\Java基础加强\\Day10\\src\\bufferedStream\\枪.mp4"));

            // 创建字节缓冲输出流
            out=new BufferedOutputStream(new FileOutputStream("D:\\Java代码\\Java基础加强\\Day10\\src\\copy.mp4"));
            int len;
                byte [] bytes=new byte[1024];
            while ((len=in.read(bytes))!=-1) {
                out.write(bytes,0,len);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        long end=System.currentTimeMillis();

        System.out.println("使用高校缓冲区,字节数组所消耗的时间是:"+(end-first)+"ms");

        /**
         * 输出结果:使用高校缓冲区,字节数组所消耗的时间是:123ms
         */


    }
}

从这可以看出高效缓冲流,字节数组是最快的方式了,复制视频音乐文件。

字符缓冲流

BufferedReader
BufferedWriter

package buffered_Reader_Writer;

import java.io.*;

/**
 *  public BufferedReader(Reader in) :创建一个 新的缓冲输入流。
 *  public BufferedWriter(Writer out) : 创建一个新的缓冲输出流。
 *
 * 用于纯文本文件.
 *  特有方法:
 * 字符缓冲流的基本方法与普通字符流调用方式一致,不再阐述,我们来看它们具备的特有方法。
 * BufferedReader: public String readLine() : 读一行文字。
 * BufferedWriter: public void newLine() : 写一行行分隔符,由系统属性定义符号
 */
public class BUfferedDemo {
    public static void main(String[] args) {
        //计算开始时间
        long first=System.currentTimeMillis();
        //创建流对象
        BufferedReader reader=null;
        BufferedWriter writer=null;
        try {
         reader=new BufferedReader(new FileReader("D:\\Java代码\\Java基础加强\\ss.txt"));
        writer=new BufferedWriter(new FileWriter("D:\\Java代码\\Java基础加强\\sss.txt"));

       String line=null;

       while ((line=reader.readLine())!=null){
           System.out.println(line);
           writer.write(line);
           writer.newLine();
       }

        } catch (IOException e) {
            e.printStackTrace();
        }
        //计算开始时间
        long end=System.currentTimeMillis();

        System.out.println("消耗时间为"+(end-first));
//比较高效读取写入,专为字符串类型的。
    }
}

文本信息恢复顺序

package buffered_Reader_Writer;

import java.io.*;
import java.util.HashMap;
import java.util.Map;

/**
 * 实现排序,要先读取文本
 * 排序当然要使用集合,内容当然要截取,用到字符串的截取操作splt()方法:\\.
 *集合存的数据为序号和内容,以便后续操作排序,因此需要使用HashMap集合
 * 遍历集合,获取集合键,使用将
 */
public class PaiXuBufferedDemo {
    public static void main(String[] args)  {
        //计算开始时间
        long first=System.currentTimeMillis();
        //创建存储序号和内容的键和值的集合
        Map map=new HashMap<>();
        //创建流对象
        try (BufferedReader reader = new BufferedReader(new FileReader("D:\\Java代码\\Java基础加强\\出师表乱序.txt"));
                BufferedWriter writer = new BufferedWriter(new FileWriter("D:\\Java代码\\Java基础加强\\出师表修正.txt"))) {

            String line = null;
            while ((line = reader.readLine()) != null) {
                // 解析文本
                String[] split = line.split("\\.");
                //将序号和内容别放入集合的键和值中
                map.put(split[0], split[1]);
            }
            for (int i = 1; i < map.size(); i++) {
                    //获取集合中的键值
                String key=String.valueOf(i);
                // 获取map中文本
                String value=map.get(key);
                // 写出拼接文本
                    writer.write(key+"."+value);
                    //换行
                    writer.newLine();

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        //计算开始时间
        long end=System.currentTimeMillis();

        System.out.println("消耗时间为"+(end-first));
        //消耗时间为79  毫秒
    }

}

转换流

InputStreamReader类
  • java.io.InputStreamReader是Reader的子类,也是从字节流到字符流的桥梁。
  • 其字符集可以由名称指定,也可以接受平台的默认字符集。

指定编码读取

package in_out_Reader_Writer;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * InputStreamReader(InputStream in) : 创建一个使用默认字符集的字符流。
 * InputStreamReader(InputStream in, String charsetName) : 创建一个指定字符集的字符流。
 */
public class InputStreamReaderDemo {

    public static void main(String[] args) throws IOException {
            // 创建流对象,默认UTF8编码
        InputStreamReader reader1 = new InputStreamReader(new FileInputStream("E:\\ssy.txt"));
        // 创建流对象,指定GBK编码
        InputStreamReader reader2 = new InputStreamReader(new FileInputStream("E:\\ssy.txt"),"gbk");

        //默认编码读取
        int le;
        while ((le=reader1.read())!=-1){

            System.out.print((char) le);
        }
        reader1.close();
        //指定编码读取
        int len;
        while ((len=reader2.read())!=-1){
                        System.out.print((char) len);
                    }
        reader2.close();

    }
}
OutputStreamWriter类
  • 转换流 java.io.OutputStreamWriter ,是Writer的子类,是从字符流到字节流的桥梁。
  • 使用指定的字符集将字符编码为字节。其字符集可以由名称指定,也可以接受平台的默认字符集。
package in_out_Reader_Writer;

import java.io.*;

/**
 * OutputStreamWriter(OutputStream in) : 创建一个使用默认字符集的字符流。
 * OutputStreamWriter(OutputStream in, String charsetName) : 创建一个指定字符集的字符流
 */
public class OutputStreamWriterDemo {
    public static void main(String[] args) throws IOException {
        OutputStreamWriter writer1=new OutputStreamWriter(new FileOutputStream("D:\\Java代码\\Java基础加强\\ms1.txt"));

        OutputStreamWriter writer2=new OutputStreamWriter(new FileOutputStream("D:\\Java代码\\Java基础加强\\ms2.txt"),"gbk");
        
            writer1.write("你好");//默认的编码为utf-8   你好  字节数为  6
            writer1.close();//你好

            writer2.write("你好");  //gbk  两个字节一个字   存储字节数为  4
            writer2.close();//���


    }

}

转换文件编码
将GBK编码的文本文件,转换为UTF-8编码的文本文件。

package in_out_Reader_Writer;

import java.io.*;

/**
 * 需求:将GBK编码的文本文件,转换为UTF-8编码的文本文件。
 *
 * 分析:
 *      1.首先需要解码-->使用gbk型,读取流
 *      2.然后需要编码-->写入时使用utf-8  写入到文本中去
 */
public class In_out_Change {
    public static void main(String[] args)  {
        //创建读取
        InputStreamReader reader =null;
        OutputStreamWriter writer=null;

        try {
            reader=new InputStreamReader(new FileInputStream("E:\\ssy.txt"),"gbk");
            writer=new OutputStreamWriter(new FileOutputStream("E:\\copySsy.txt"),"utf-8");
            //定义长度
            int len;
            //定义数组
          char [] chars=new char[1024];
          //循环读取
            while ((len=reader.read(chars))!=-1){
                // 循环写出
                writer.write(chars,0,len);
            }

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

    }
}

总结:
缓冲区的原理:
1.使用了底层流对象从具体设备上获取数据,并将数据存储到缓冲区中的数据内。
2.通过缓冲区的read方法从缓冲区来获取具体的字符数据,这样就提高了数据。
3.如果用read()方法读取字符数据,并存储到另一个容器中,直到读到了换行符时,另一个容器的临时存储的数据转成字符串返回,就形成了readLine()功能。

你可能感兴趣的:(2019-03-04)