J04-Java IO流总结二《 FileReader和FileWriter 》

FileReader和FileWriter的源码非常简单,下面通过分析它们的源码以更好地进行理解这两个流

1. FileReader

FileReader实现了读取底层的字节数据并将其转换为字符数据的功能,转换时依赖的字符集为平台默认的字符集GBK(Windows平台)。

FileReader源码如下:

public class FileReader extends InputStreamReader {

    public FileReader(String fileName) throws FileNotFoundException {
        super(new FileInputStream(fileName));
    }

    public FileReader(File file) throws FileNotFoundException {
        super(new FileInputStream(file));
    }

    public FileReader(FileDescriptor fd) {
        super(new FileInputStream(fd));
    }
}

  由源码不难看出,FileReader类继承自InputStreamReader类,它自己只提供了几个构造方法,它的构造方法中又通过super来调用父类构造器以构建流对象,它本身没有再提供其他的读取流数据的方法,全部继承它的直接父类InputStreamReader,而InputStreamReader又是继承自Reader类,因此FileReader和InputStreamReader一样,都能使用read()、read(char cbuf[])、read(char cbuf[], int off, int len)方法来读取流数据

  此外,由源码可知,FileReader的读取字符串的功能是通过转换流InputStreamReader类实现的:首先InputStreamReader包装了一个FileInputStream从文件读取字节数据,再将其转换为字符,FileReader继承了InputStreamReader,从而也获得了该功能。我们截取该类的其中一个构造方法的代码出来:

    public FileReader(String fileName) throws FileNotFoundException {
        super(new FileInputStream(fileName));
    }

  可以看到,在调用父类InputStreamReader转换流的构造方法时,没有显式地指定解码所需的字符集,因此使用的是平台默认字符集来将读到的字节数据转换为字符。因此,FileReader去读取GBK编码的源文件数据时不会出现乱码,而在读取UTF-8等其他字符集编码的文件时就会粗现乱码了。

  从该流的API文档同样可以看出这点:FileReader是用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。要自己指定这些值,可以先在 FileInputStream 上构造一个 InputStreamReader。 FileReader 用于读取字符流。要读取原始字节流,请考虑使用 FileInputStream。

综上,可知FileReader的本质其实还是字节流

FileReader类使用示例代码:

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

public class FileReaderTest {
    public static void main(String[] args) {

        System.out.println("【从GBK文件读取到的内容】:");
        test1();
        System.out.println("\n\n【从UTF-8文件读取到的内容】:");
        test2();

    }

    ////////////////////////////////////////////////////////////
    /**
     * 使用FileReader从编码为GBK的源文件1.txt中读取数据,能正确读取
     */
    private static void test1() {
        FileReader fr = null;

        try {
            fr = new FileReader("./src/res/1.txt");

            int value = 0;

            while(-1 != (value = fr.read())) {  //使用read()方法读取
                System.out.print((char)value);
            }

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

    ////////////////////////////////////////////////////////////
    /**
     * 使用FileReader从编码为utf-8的源文件2.txt中读取数据,将出现乱码
     */
    private static void test2() {
        FileReader fr = null;

        try {
            fr = new FileReader("./src/res/2.txt");

            int len = 0;
            char[] buf = new char[1024];    //注意这里是字符数组!!

            while(-1 != (len = fr.read(buf))) { //使用read(char cbuf[])方法读取
                System.out.println(new String(buf));
            }

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

代码运行效果:

【从GBK文件读取到的内容】:
hello java hello hello 中国

【从UTF-8文件读取到的内容】:
hello java hello hello 涓浗

  可见,若是使用FileReader从UTF-8文件中读取数据,将会出现乱码,原因我们在上面也说了,是因为FileReader的底层转换流InputStreamReader在将字节数据转换为字符数据时,使用的是平台默认的字符集GBK,与源文件的不一致,由此导致了乱码。

2. FileWriter

  FileWriter实现了将字符数据转换为字节数据的功能。它所依赖的字符集也是平台默认的GBK 。

  该流的API文档有如下描述:用来写入字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的。要自己指定这些值,可以先在 FileOutputStream 上构造一个 OutputStreamWriter。

FileWriter源码如下:

public class FileWriter extends OutputStreamWriter {

    public FileWriter(String fileName) throws IOException {
        super(new FileOutputStream(fileName));
    }

    public FileWriter(String fileName, boolean append) throws IOException {
        super(new FileOutputStream(fileName, append));
    }

    public FileWriter(File file) throws IOException {
        super(new FileOutputStream(file));
    }

    public FileWriter(File file, boolean append) throws IOException {
        super(new FileOutputStream(file, append));
    }

    public FileWriter(FileDescriptor fd) {
        super(new FileOutputStream(fd));
    }

}

  由FileWriter的源码可以看到,该类的直接父类是转换流OutputStreamWriter,它跟FileReader简直一模一样——自己只提供了几个构造方法,并在它的构造方法中又通过super来调用父类构造器以构建流对象,它本身没有再提供其他的写出流数据的方法,全部继承它的直接父类OutputStreamWriter,而OutputStreamWriter又是继承自Writer类,因此FileWriter和OutputStreamWriter一样,都能使用write(int c)、write(char cbuf[])、write(char cbuf[], int off, int len)、write(String str)、write(String str, int off, int len)方法来写入流数据

FileWriter流使用示例代码:

import java.io.FileWriter;
import java.io.IOException;

public class FileWriterTest {
    public static void main(String[] args) {
        FileWriter fw = null;

        try {
            fw = new FileWriter("./src/res/3.txt");

            String str1 = "hello java";
            String str2 = "中国";

            char[] array = str1.toCharArray();//将字符串转换为字符数组

            fw.write(str1, 0, 5);   //写入:hello
            fw.write(str2);         //写入:中国
            fw.write(array);        //写入:hello java
            fw.write(array, 6, 4);  //写入:java

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

代码运行效果:

本次示例中,是将数据写入GBK编码的目标文件中,倘若目标是UTF-8或者其他编码,则写入的数据中文会发生乱码,如下所示:

使用FileReader和FileWriter在两个文件之间相互拷贝文件的操作跟前边的示例差不多,这里不再写了。

3. 小结

FileInputStream、FileOutputStream、FileReader和FileWriter都是跟磁盘文件有关的字节流但凡需要跟磁盘文件进行I/O操作的,必将使用到它们中的其中一个!需要根据读取的是字节流还是字符流来进行相应的选择。

原文地址:https://www.cnblogs.com/suhaha/p/9651484.html

时间: 2024-11-09 14:55:31

J04-Java IO流总结二《 FileReader和FileWriter 》的相关文章

java IO流(二)

 IO流主要用于硬板.内存.键盘等处理设备上得数据操作,根据处理数据的数据类型的不同可以分为:字节流(抽象基类为InputStream和OutputStream)和字符流(抽象基类为Reader和Writer).根据流向不同,可以分为:输入流和输出流.一般探讨IO流时,是按数据类型来分的. IO流的分类: 流向: 输入流  (读取数据) 输出流  (写出数据) 数据类型: 字节流  字节输入流(读取数据) InputStream 字节输出流 (写出数据)OutputStream 字符流 字符输入

Java IO 流(二)

InputStream和OutputStream的对应关系如下: 这里针对每一个类,分别做一些实例和介绍:1.InputStream.OutputSTream InputStream\OutSTream是抽象类,定义了关于字节流操作的最基本的方法InputStream: available() / read() / mark() /reset() / skip() / markSupported() / close()OutputStream: 2.ByteArrayInputStream.By

《二》Java IO 流的分类介绍

一.根据流向分为输入流和输出流: 注意输入流和输出流是相对于程序而言的. 输出:把程序(内存)中的内容输出到磁盘.光盘等存储设备中        输入:读取外部数据(磁盘.光盘等存储设备的数据)到程序(内存)中 综合起来:   二.根据传输数据单位分为字节流和字符流 上面的也是 Java IO流中的四大基流.这四大基流都是抽象类,其他流都是继承于这四大基流的.   三.根据功能分为节点流和包装流 节点流:可以从或向一个特定的地方(节点)读写数据.如FileReader. 处理流:是对一个已存在的

Java IO流(二)

目录 Java IO流(二) 7. 字节缓冲流 7.1 概述 7.2 BufferedOutputStream类 7.3 BufferedInputStream类 8. 文件复制练习(增强版 使用缓冲流) 9. 字符缓冲流 9.1 BufferedWriter类 9.2 BufferedReader类 10. 练习:文本排序 11. 转换流 11.1 字符编码和字符集 11.2 编码引出的问题 11.3 转换流的原理 11.4 OutputStreamWriter类 11.5 InputStre

Java IO流详解(二)——File类

在上一章博客中简单的介绍了Java IO流的一些特征.也就是对文件的输入输出,既然至始至终都离不开文件,所以Java IO流的使用得从File这个类讲起. File类的描述:File类是文件和目录路径名的抽象表示形式,主要用于文件和目录的创建.查找和删除等操作.即Java中把文件或者目录(文件夹)都封装成File对象.也就是说如果我们要去操作硬盘上的文件或者目录只要创建File这个类即可. 不过要注意的是File类只是对文件的操作类,只能对文件本身进行操作,不能对文件内容进行操作. 1.File

装饰器模式及JAVA IO流例子★★★☆☆

一.什么是装饰模式 通过关联机制给类增加行为,其行为的扩展由修饰对象来决定: 二.补充说明 与继承相似,不同点在于继承是在编译期间扩展父类,而装饰器模式在运行期间动态扩展原有对象: 或者说,继承是对类进行扩展,装饰模式是对对象进行扩展: 三.角色 抽象构件 具体构件 抽象装饰类 具体装饰类 说明:具体构件.抽象装饰类.具体装饰类的共同父类是抽象构件,具体装饰类继承抽象装饰类并在运行期间装饰具体构件: 四.例子 例子说明: 画家接口Painter,为抽象构件,有两个方法,获取画家描述信息及绘画:

黑马程序员-Java IO流

--Java培训.Android培训.iOS培训..Net培训.期待与您交流!-- 一.概述 Java中与IO相关的类有很多,都集中在java.io中,都是以流的形式操作的,流是有一定的顺序,像一个管道一样,它的本质是传输数据.根据数据类型的不同可以分为字节流和字符流,根据流向的不同可以分为输入流和输出流. 字符流:因为数据有不同的编码,可以对字符进行不同的操作,其本质还是基于字节流,然后再查询相应的码表.一般用于处理纯文本数据. 字节流:可以处理所有类型数据,二进制文件(图片,音频等). 输入

学习笔记-java IO流总结 转载

1.什么是IO Java中I/O操作主要是指使用Java进行输入,输出操作. Java所有的I/O机制都是基于数据流进行输入输出,这些数据流表示了字符或者字节数据的流动序列.Java的I/O流提供了读写数据的标准方法.任何Java中表示数据源的对象都会提供以数据流的方式读写它的数据的方法. Java.io是大多数面向数据流的输入/输出类的主要软件包.此外,Java也对块传输提供支持,在核心库 java.nio中采用的便是块IO. 流IO的好处是简单易用,缺点是效率较低.块IO效率很高,但编程比较

java io流 分析

java io流 在java应用或者android应用中很常见,并且使用频率很高的一个模块.当时每次需要用到这个模块的时候总是有提笔忘字的感觉,不知道该用哪个流或者该用谁包装谁. 所以我就花了一点时间把这个块的结构梳理了一下.一是能让自己理清一下思路.二是以后如果还有提笔忘字的时候,看这篇文章就好了. 首先java io流分两大系统InputStream 和Reader,前者及其子类主要用于读取字节流,后者及其子类主要用于读取字符流.下面是InputSteram系的继承树 首先可以看InputS

java IO流详解(一)

从本篇博文开始,详细讲解JAVA IO流的基本操作,力求每一个例子都给大家一个DEMO,在最终完成的时候,我会贴出最终的源码,方便大家交流学习. 上一篇博文中转载了大神的博文和图片,非常好! 文章链接如下:Java IO流 下面一个个的用实例进行讲解每个IO流的基本用法. 1 File文件 public static void main(String[] args) throws IOException { File file = new File("."); myPrint(file