• Java IO流详解(四)——字符流Reader和Writer


        前面一章介绍了字节流的使用,提到了字节流在处理utf-8编码的中文可能会出现乱码的情况(其他编码的中文同样会出现乱码),所以Java针对这一情况提供了字符流。

        但是字符流只能处理字符,不能用来处理 .jpg;.mp3;.mp4;.avi;.doc;.ppt等二进制文件,这些只能通过字节流来处理。所以对于纯文本的文件,强烈推荐使用字符输入输出流。

        字符流的本质其实就是基于字节流在读取时去查了指定的码表。


    1、字符输入流Reader

        Reader是所有字符输入流的父类,定义了所有字符输入流都具有的共同特征。其内部提供的方法如下:

    image

    上图中重载的三个read()方法都是用来读数据的。

    • int read():每次读取一个字符,并把它转换为 0~65535 的整数,然后返回读取到的字符。读到末尾返回-1。(为了提高 I/O 操作的效率,建议尽量使用下面两种read()方法)
    • int read(char[] cbuf):将读取到的多个字符存储到 cbuf 中,然后返回读取的字符,读到末尾时返回-1。
    • int read(char[] cbuf,int off,int len):将读取到的多个字符存储进字符数组 cbuf,从索引 off 开始,长度为len字符,返回结果为读取的字符数.


    其中Reader的子类FileReader是专门用于读取文件中的数据,通过它将目标设备上的数据读入到程序。

      FileReader读入文件举例(读取的hello.txt文件内容是:你好,我是中国人!):

    package com.thr;
    
    import java.io.File;
    import java.io.FileReader;
    import java.io.IOException;
    
    /**
     * @author Administrator
     * @date 2020-02-23
     * @desc 字符输入流FileReader
     */
    public class FileReaderTest {
    
        public static void main(String[] args)  {
            //定义输入流
            FileReader fr =null;
            try {
                //1、创建文件对象
                File file = new File("D:\IO\hello.txt");
                //2、创建输入流对象
                fr = new FileReader(file);
    
                //循环读取,读取到末尾返回-1
                int len ;//记录每次读取的字节个数
                while((len = fr.read())!=-1){
                    System.out.print((char)len);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //释放资源
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    运行结果:
    你好,我是中国人!


    2、字符输出流Writer

        Writer是所有字符输出流的父类,定义了所有字符输出流都具有的共同特征。其内部提供的方法如下:

    image

    上图中重载的五个write()方法都是用来写数据的。

    • void write(int c):把一个字符写入到文件中。
    • void write(char[] cbuf):把cbuf字符数组写入到文件中。
    • void write(char[] cbuf,int off,int len):把部分字符数组写入到文件中,从 cbuf 数组的 off 索引开始,写入len个字符。
    • void write(String str):把一个字符串写入到文件中。
    • void write(String str,int off,int len):把部分字符串写入到文件中,从 字符串的 off 索引开始,写入len个字符。


    其中Writer的子类FileWriter是门用于读出文件中的数据,通过它将数据从程序输出到目标设备。

        FileWriter输出文件举例:

    package com.thr;
    
    import java.io.File;
    import java.io.FileWriter;
    import java.io.IOException;
    
    /**
     * @author Administrator
     * @date 2020-02-23
     * @desc 字符输出流FileWriter
     */
    public class FileWriterTest {
    
        public static void main(String[] args)  {
            //定义输出流
            FileWriter fw =null;
            try {
                //1、创建文件对象
                File file = new File("D:\IO\a.txt");
                //2、创建输出流对象,保留原来的数据,在文件后面追加
                fw = new FileWriter(file,true);
    
                //write():写出一个字符(utf-8编码)
                fw.write(20200223);
                fw.write("
    ");//回车换行
    
                //write(char[] buffer):把cbuf字符数组写入到文件中。
                fw.write("我是中国人".toCharArray());
                fw.write("
    ");
    
                //write(char[] cbuf,int off,int len):把部分字符数组写入到文件中,从 cbuf 数组的 off 索引开始,写入len个字符。
                fw.write("我是中国人".toCharArray(),1,4);
                fw.write("
    ");
    
                //write(String str):把一个字符串写入到文件中。
                fw.write("中国人");
                fw.write("
    ");
    
                //write(String str,int off,int len):把部分字符串写入到文件中,从 字符串的 off 索引开始,写入len个字符。
                fw.write("你好,我是中国人
    ",3,6);
    
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //释放资源
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

        注意:如果字符输出流不调用close()方法关闭资源,数据只是保存到缓冲区,并不会保存到文件(这一点与FileOutputStream不同,即使它不调用close()方法依然会写入到文件中)。

        这里就得介绍一下flush()这个方法。

        flush()和close()方法的区别:

        flush():将流中的缓冲区缓冲的数据刷新到目的地中,刷新后,流还可以继续使用。

        close():关闭资源,但在关闭前会将缓冲区中的数据先刷新到目的地,否则丢失数据,然后在关闭流。流不可以使用。

        而当我们亲自去使用flush()方法的时候会产生一个疑问,就算我们在close()之前不加flush()方法也不会影响文件的写出呀,那为什么还要用这个方法呢?先看一下下面的代码吧:

    package com.thr;
    
    import java.io.FileWriter;
    import java.io.IOException;
    
    /**
     * @author Administrator
     * @date 2020-02-24
     * @desc flush方法的使用
     */
    public class WriterFlushTest {
    
            public static void main(String[] args) {
    
                //定义输出流
                FileWriter fw = null;
    
                //其实该步就是在明确数据要存放的目的地
                try {
                    fw=new FileWriter("D:\flush.txt");
                    fw.write("");//调用write方法,将字符串写入到流中(使用write其实并没有将字符串直接写入到指定文件,而是存放在流中)
                    fw.flush();//这一步才是将上一步write的所写的字符串冲刷到指定的文件(在指定的文件打开后有字符串存在了)
    
                    fw.write("");
                    fw.flush();
    
                    fw.write("flush方法");
                    fw.flush();
    
                    fw.close();//close()是一定要做的(其实close方法中调用了flush方法)
    
                    fw.write("CCC");//close后若再write,会提示IO异常Stream closed
    
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    }
    

           小声BB:我认为flush()方法可有可无,它就是将缓冲区的数据强制写入到文件中,因为在调用完write()方法后数据并没有写入到文件中,而是保存在流中,此时我们可以调用flush()方法,也可以在最后用close()方法来将数据写入文件,因为在close()的时候,也会进行一次flush的,因此close之前其实可以不用专门做flush的。但是在某些情况下,数据量较大的时候,在写的过程中,可以进行阶段性的flush。(话说我也不知道这样做会有什么好处……006DDA0B006DDA0B006DDA0B


    3、字符流拷贝文件

    package com.thr;
    
    import java.io.File;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    
    /**
     * @author Administrator
     * @date 2020-02-23
     * @desc 拷贝文本文件
     */
    public class FileReaderWriterTest {
    
        public static void main(String[] args)  {
            //定义输入流
            FileReader fr =null;
            //定义输出流
            FileWriter fw =null;
            try {
                //创建读入文件对象
                File f1 = new File("D:\IO\hello.txt");
                //创建读出文件对象
                File f2 = new File("C:\a.txt");
    
                fr = new FileReader(f1);
                fw = new FileWriter(f2);
    
                //循环读取,读取到末尾返回-1
                char chars[] = new char[1024];
                int len ;//记录每次读取的字节个数
                while((len = fr.read(chars))!=-1){
                    fw.write(chars,0,len);
                }
                System.out.println("拷贝成功...");
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //释放资源
                try {
                    fr.close();
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
  • 相关阅读:
    Entity Framework 异常: 'OFFSET' 附近有语法错误。 在 FETCH 语句中选项 NEXT 的用法无效。 关键字 'AS' 附近有语法错误。
    C#开源大全--汇总(转)
    C#开源系统大汇总(转)
    迁移博客园文章通知
    kickstart配置LINUX无人值守选项--rootpw
    linux 系统网卡无法识别,缺少驱动
    NFS服务简介
    linux下vim命令详解
    vim 中替换命令
    在CentOS/RHEL 6.4上安装Chromium
  • 原文地址:https://www.cnblogs.com/tanghaorong/p/12345255.html
Copyright © 2020-2023  润新知