java基础(24):转换流、缓冲流

1. 转换流

在学习字符流(FileReader、FileWriter)的时候,其中说若是须要指定编码和缓冲区大小时,能够在字节流的基础上,构造一个InputStreamReader或者OutputStreamWriter,这又是什么意思呢?数组

 

1.1 OutputStreamWriter

 

查阅OutputStreamWriterAPI介绍,OutputStreamWriter 是字符流通向字节流的桥梁:可以使用指定的字符编码表,将要写入流中的字符编码成字节。它的做用的就是,将字符串按照指定的编码表转成字节,在使用字节流将这些字节写出去。网络

 

代码演示:学习

public static void writeCN() throws Exception { //建立与文件关联的字节输出流对象
        FileOutputStream fos = new FileOutputStream("c:\\cn8.txt"); //建立能够把字符转成字节的转换流对象,并指定编码
        OutputStreamWriter osw = new OutputStreamWriter(fos,"utf-8"); //调用转换流,把文字写出去,实际上是写到转换流的缓冲区中
        osw.write("你好");//写入缓冲区。
 osw.close(); }

OutputStreamWriter流对象,它到底如何把字符转成字节输出的呢?编码

其实在OutputStreamWriter流中维护本身的缓冲区,当咱们调用OutputStreamWriter对象的write方法时,会拿着字符到指定的码表中进行查询,把查到的字符编码值转成字节数存放到OutputStreamWriter缓冲区中。而后再调用刷新功能,或者关闭流,或者缓冲区存满后会把缓冲区中的字节数据使用字节流写到指定的文件中。spa

1.2 InputStreamReader

查阅InputStreamReaderAPI介绍,InputStreamReader 是字节流通向字符流的桥梁:它使用指定的字符编码表读取字节并将其解码为字符。它使用的字符集能够由名称指定或显式给定,或者能够接受平台默认的字符集。3d

 

 

代码演示code

 

public class InputStreamReaderDemo { public static void main(String[] args) throws IOException { //演示字节转字符流的转换流
 readCN(); } public static void readCN() throws IOException{ //建立读取文件的字节流对象
        InputStream in = new FileInputStream("c:\\cn8.txt"); //建立转换流对象 //InputStreamReader isr = new InputStreamReader(in);这样建立对象,会用本地默认码表读取,将会发生错误解码的错误
        InputStreamReader isr = new InputStreamReader(in,"utf-8"); //使用转换流去读字节流中的字节
        int ch = 0; while((ch = isr.read())!=-1){ System.out.println((char)ch); } //关闭流
 isr.close(); } }

注意:在读取指定的编码的文件时,必定要指定编码格式,不然就会发生解码错误,而发生乱码现象。对象

1.3 转换流和子类区别

发现有以下继承关系:blog

OutputStreamWriter:继承

  |--FileWriter:

InputStreamReader:

  |--FileReader;

 

父类和子类的功能有什么区别呢?

OutputStreamWriterInputStreamReader是字符和字节的桥梁:也能够称之为字符转换流。字符转换流原理:字节流+编码表。

FileWriterFileReader:做为子类,仅做为操做字符文件的便捷类存在。当操做的字符文件,使用的是默认编码表时能够不用父类,而直接用子类就完成操做了,简化了代码。

InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//默认字符集。

InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");//指定GBK字符集。

FileReader fr = new FileReader("a.txt");

这三句代码的功能是同样的,其中第三句最为便捷。

注意:一旦要指定其余编码时,绝对不能用子类,必须使用字符转换流。何时用子类呢?

条件:

1、操做的是文件。2、使用默认编码。

总结:

字节--->字符 : 看不懂的--->看的懂的。  须要读。输入流。 InputStreamReader

字符--->字节 : 看的懂的--->看不懂的。  须要写。输出流。 OutputStreamWriter

2. 缓冲流

在咱们学习字节流与字符流的时候,你们都进行过读取文件中数据的操做,读取数据量大的文件时,读取的速度会很慢,很影响咱们程序的效率,那么,我想提升速度,怎么办?

Java中提升了一套缓冲流,它的存在,可提升IO流的读写速度

缓冲流,根据流的分类分类字节缓冲流与字符缓冲流。

2.1 字节缓冲流

字节缓冲流根据流的方向,共有2

写入数据到流中,字节缓冲输出流 BufferedOutputStream

读取流中的数据,字节缓冲输入流 BufferedInputStream

 

它们的内部都包含了一个缓冲区,经过缓冲区读写,就能够提升了IO流的读写速度

2.1.1 字节缓冲输出流BufferedOutputStream

经过字节缓冲流,进行文件的读写操做 写数据到文件的操做  

构造方法

public BufferedOutputStream(OutputStream out)建立一个新的缓冲输出流,以将数据写入指定的底层输出流。 

public class BufferedOutputStreamDemo01 { public static void main(String[] args) throws IOException { //写数据到文件的方法
 write(); } /* * 写数据到文件的方法 * 1,建立流 * 2,写数据 * 3,关闭流 */
    private static void write() throws IOException { //建立基本的字节输出流
        FileOutputStream fileOut = new FileOutputStream("abc.txt"); //使用高效的流,把基本的流进行封装,实现速度的提高
        BufferedOutputStream out = new BufferedOutputStream(fileOut); //2,写数据
        out.write("hello".getBytes()); //3,关闭流
 out.close(); } }

2.1.2 字节缓冲输入流 BufferedInputStream

刚刚咱们学习了输出流实现了向文件中写数据的操做,那么,如今咱们完成读取文件中数据的操做

构造方法

public BufferedInputStream(InputStream in) 

/* * 从文件中读取数据 * 1,建立缓冲流对象 * 2,读数据,打印 * 3,关闭  */
private static void read() throws IOException { //1,建立缓冲流对象
        FileInputStream fileIn = new FileInputStream("abc.txt"); //把基本的流包装成高效的流
        BufferedInputStream in = new BufferedInputStream(fileIn); //2,读数据
        int ch = -1; while ( (ch = in.read()) != -1 ) { //打印
            System.out.print((char)ch); } //3,关闭
 in.close(); }

2.1.3 使用基本的流与高效的流完成复制文件

咱们一直在说,高效的流速度快并高效,怎么体现呢?须要经过一个复制文件耗时的比较过程,来体验一下高效流带来的快感。

/* * 需求:将d:\\test.avi文件进行复制 * 采用4种方式复制 * 方式1: 采用基本的流,一次一个字节的方式复制 共耗时 224613毫秒 * 方式2: 采用基本的流,一个多个字节的方式赋值 共耗时 327毫秒 * 方式3: 采用高效的流,一次一个字节的方式复制 共耗时 2047毫秒 * 方式4: 采用高效的流,一个多个字节的方式赋值 共耗时 96毫秒 * * 数据源: d:\\test.avi * 目的地1: d:\\copy1.avi * 目的地2: d:\\copy2.avi * 目的地3: d:\\copy3.avi * 目的地4: d:\\copy4.avi * * 实现的步骤: * 1,指定数据源 * 2,指定目的地 * 3,读数据 * 4,写数据 * 5,关闭流 * */
public class CopyAVI { public static void main(String[] args) throws IOException { //开始计时
        long start = System.currentTimeMillis(); //方式1: 采用基本的流,一次一个字节的方式复制 //method1("d:\\test.avi", "d:\\copy1.avi"); //方式2: 采用基本的流,一个多个字节的方式赋值 //method2("d:\\test.avi", "d:\\copy2.avi"); //方式3: 采用高效的流,一次一个字节的方式复制 //method3("d:\\test.avi", "d:\\copy3.avi"); //方式4: 采用高效的流,一个多个字节的方式赋值
        method4("d:\\test.avi", "d:\\copy4.avi"); //结束计时
        long end = System.currentTimeMillis(); //打印耗时多少毫秒
        System.out.println("共耗时 " +(end - start)+ "毫秒"); } //方式4: 采用高效的流,一个多个字节的方式赋值
    private static void method4(String src, String dest) throws IOException { //1,指定数据源
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(src)); //2,指定目的地
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest)); //3,读数据
        byte[] buffer = new byte[1024]; int len = -1; while ( (len = in.read(buffer)) != -1) { //4,写数据
            out.write(buffer, 0, len); } //5,关闭流
 in.close(); out.close(); } //方式3: 采用高效的流,一次一个字节的方式复制
    private static void method3(String src, String dest) throws IOException { //1,指定数据源
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(src)); //2,指定目的地
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest)); //3,读数据
        int ch = -1; while ((ch=in.read()) != -1) { //4,写数据
 out.write(ch); } //5,关闭流
 in.close(); out.close(); } //方式2: 采用基本的流,一个多个字节的方式赋值
    private static void method2(String src, String dest) throws IOException { //1,指定数据源
        FileInputStream in = new FileInputStream(src); //2,指定目的地
        FileOutputStream out = new FileOutputStream(dest); //3,读数据
        byte[] buffer = new byte[1024]; int len = -1; while ( (len=in.read(buffer)) != -1) { //4,写数据
            out.write(buffer, 0, len); } //5,关闭流
 in.close(); out.close(); } //方式1: 采用基本的流,一次一个字节的方式复制
    private static void method1(String src, String dest) throws IOException { //1,指定数据源
        FileInputStream in = new FileInputStream(src); //2,指定目的地
        FileOutputStream out = new FileOutputStream(dest); //3,读数据
        int ch = -1; while (( ch=in.read()) != -1) { //4,写数据
 out.write(ch); } //5,关闭流
 in.close(); out.close(); } }

2.2 字符缓冲流

字符缓冲输入流 BufferedReader

字符缓冲输出流 BufferedWriter

完成文本数据的高效的写入与读取的操做

2.2.1 字符缓冲输出流 BufferedWriter

将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入

方法:

void newLine() 根据当前的系统,写入一个换行符

/* * BufferedWriter 字符缓冲输出流 * 方法 * public void newLine()写入一个行分隔符 * * 需求: 经过缓冲输出流写入数据到文件 * 分析: * 1,建立流对象 * 2,写数据 * 3,关闭流 * */
public class BufferedWriterDemo { public static void main(String[] args) throws IOException { //建立流 //基本字符输出流
        FileWriter fileOut = new FileWriter("file.txt"); //把基本的流进行包装
        BufferedWriter out = new BufferedWriter(fileOut); //2,写数据
        for (int i=0; i<5; i++) { out.write("hello"); out.newLine(); } //3,关闭流
 out.close(); } }

2.2.2 字符缓冲输入流 BufferedReader

从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。

方法

public String readLine() 读取一个文本行包含该行内容的字符串,不包含任何行终止符,若是已到达流末尾,则返回 null

/* * BufferedReader 字符缓冲输入流 * * 方法: * String readLine() * 需求:从文件中读取数据,并显示数据 */
public class BufferedReaderDemo { public static void main(String[] args) throws IOException { //1,建立流
        BufferedReader in = new BufferedReader(new FileReader("file.txt")); //2,读数据 //一次一个字符 //一次一个字符数组 //一次读取文本中一行的字符串内容
        String line = null; while( (line = in.readLine()) != null ){ System.out.println(line); } //3,关闭流
 in.close(); } }

2.2.3 使用字符缓冲流完成文本文件的复制

刚刚咱们学习完了缓冲流,如今咱们就使用字符缓冲流的特有功能,完成文本文件的复制

/* * 采用高效的字符缓冲流,完成文本文件的赋值 * * 数据源: file.txt * 目的地: copyFile.txt * * 分析: * 1,指定数据源, 是数据源中读数据,采用输入流 * 2,指定目的地,是把数据写入目的地,采用输出流 * 3,读数据 * 4,写数据 * 5,关闭流 */
public class CopyTextFile { public static void main(String[] args) throws IOException { //1,指定数据源, 是数据源中读数据,采用输入流
        BufferedReader in = new BufferedReader(new FileReader("file.txt")); //2,指定目的地,是把数据写入目的地,采用输出流
        BufferedWriter out = new BufferedWriter(new FileWriter("copyFile.txt")); //3,读数据
        String line = null; while ( (line = in.readLine()) != null ) { //4,写数据
 out.write(line); //写入换行符号
 out.newLine(); } //5,关闭流
 out.close(); in.close(); } }

3. 流的操做规律

IO流中对象不少,解决问题(处理设备上的数据时)到底该用哪一个对象呢?  

IO流进行了规律的总结(四个明确)

明确一:要操做的数据是数据源仍是数据目的。

  源:InputStream    Reader

  目的:OutputStream Writer

先根据需求明确要读,仍是要写。

 

明确二:要操做的数据是字节仍是文本呢?

源:

  字节:InputStream

  文本:Reader

目的:

  字节:OutputStream

  文本:Writer

已经明确到了具体的体系上。

 

明确三:明确数据所在的具体设备。

源设备:

  硬盘:文件  File开头。

  内存:数组,字符串。

  键盘:System.in;

  网络:Socket

目的设备:

  硬盘:文件  File开头。

  内存:数组,字符串。

  屏幕:System.out

  网络:Socket

彻底能够明确具体要使用哪一个流对象。

 

l 明确四:是否须要额外功能呢?

额外功能:

  转换吗?转换流。InputStreamReader OutputStreamWriter

  高效吗?缓冲区对象。BufferedXXX

InputStream

       FileInputStream

       BufferedInputStream

OuputStream

  FileOutputStream

  BufferedOuputStream

Writer

  OutputStreamWriter

  FileWriter

  BufferedWriter

Reader

  InputStreamReader

  FileReader

  BufferedReader

相关文章
相关标签/搜索