当前位置:   article > 正文

Java I/O流复习(二)—字符流、字符缓冲流、以及和字节流的区别_缓冲字符流和字符流的区别

缓冲字符流和字符流的区别

Java I/O流复习(二)

1 字符输入流

字符流(Java IO的Reader和Writer)功能与InputStream和OutputStream非常类似,InputStream和OutputStream基于字节处理,而字符流(Reader和Writer)是基于字符处理。主要用于读写文本。

1.1 Reader 类的常用方法

Reader类是Java IO中所有Reader的基类。子类包括FileReader,BufferedReader,InputStreamReader,StringReader和其他Reader。

  1. read() ; 读取字符输入流。读取字符输入流的下一个字符,返回一个字符,意味着这个返回值的范围在0到65535之间(当达到流末尾时,同样返回-1)。这并不意味着Reader只会从数据源中一次读取2个字节,Reader会根据文本的编码,一次读取一个或者多个字节。
  2. read(char cbuf[]);读取字符输入流。读取多个字符,存入字符数组cbuf,返回实际读入的字符数。
  3. read(char cbuf[], int off, int len); 方法,读取字符输入流。每次读取len个字符,存入字符数组cbuf,从off下标开始存储。
  4. close(); 关闭当前流,释放与该流相关的资源,防止资源泄露。在带资源的try语句中将被自动调用。关闭流之后还试图读取字符,会出现IOException异常。

1.2 Reader类的子类:FileReader

FileReader类从InputStreamReader类继承而来(间接继承了Reader)。该类按字符读取流中数据。

1.3 FileReader构造方法和常用方法

1.3.1 构造方法
  1. FileReader(File file);通过打开一个到实际文件的连接来创建一个FileReader,该文件通过文件系统中的 File 对象 file 指定。

  2. FileReader(String fileName) ; 通过打开一个到实际文件的连接来创建一个FileReader,该文件通过文件系统中的路径名 name 指定。

  3. (了解)FileReader(FileDescriptor fd) ; 在给定从中读取数据的FileDescriptor 的情况下创建一个新 FileReader。

    提示:FileDescriptor 是“文件描述符”。

    其中有三个属性:

    1. in 标准输入(键盘)的描述符(从键盘输入读取流)
    2. out 标准输出(屏幕)的描述符(讲流输出到控制台上)
    3. err 标准错误输出(屏幕)的描述符(将流以红色的字体输出到控制台上)

    代码示例:

    try {
       FileWriter fw = new FileWriter(FileDescriptor.out);
       fw.write("我是爱你的。");
       fw.flush();
       fw.close();
    }...
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    控制台输出:

1.3.2 常用方法

test.txt 文件内容(字符长度为17)

  1. read();读取字符输入流。读取字符输入流的下一个字符,返回一个字符。

    try {
    File file = new File("test.txt");
    FileReader fileReader = new FileReader(file);
    int read = fileReader.read();//默认第一次读取第一个字符
    System.out.println((char)read);
    }...
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    结果:

  2. read(char cbuf[]);读取字符输入流。读取多个字符,存入字符数组cbuf,返回实际读入的字符数。

    try {
    File file = new File("test.txt");
    FileReader fileReader = new FileReader(file);
    
    char c [] = new char[20];
    int len = fileReader.read(c);//
    System.out.println("读取的字符长度为:"+len);
    
    for (char d : c) {
        System.out.print(d);
    }
    }...
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    结果:

  3. read(char cbuf[], int off, int len);读取字符输入流。每次读取len个字符,存入字符数组cbuf,从off下标开始存储。

    try {
    File file = new File("test.txt");
    FileReader fileReader = new FileReader(file);
    
    char c [] = new char[20];
    int len = fileReader.read(c,2,8);//读取8个字符存入c数组,从下标2开始存储
    System.out.println("读取的字符长度为:"+len);
    
    for (char d : c) {
        System.out.print(d);
    }
    
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    结果:

  4. close();关闭当前流,释放与该流相关的资源,防止资源泄露。在带资源的try语句中将被自动调用。关闭流之后还试图读取字符,会出现IOException异常。

    try {
    File file = new File("test.txt");
    FileReader fileReader = new FileReader(file);
    int read = fileReader.read();//
    System.out.println((char)read);
    fileReader.close();//通过close()来关闭流,以释放系统资源。
    }...
    //或者在这里关闭
     ...finally {
        if(fileReader!=null)
            fileReader.close();
     }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    注意:

    1. 通常不使用close会导致内存泄露,垃圾回收机制会回收,但是最好自己显式关闭
    2. OutputStream的作用是如FileOutStream,当不调用close的时候,不会将缓存刷入文件中。

    所以:一般使用完IO流之后都要通过close()来关闭,以释放系统资源

2 字符输出流

2.1 Writer类的常用方法

  1. write (String str); 将指定的字符串写入此输出流。
  2. write(char[] cbuf, int off, int len); 将指定 char 数组中从偏移量 off 开始的 len 个字符写入此输出流。
  3. flush(); 用于清空缓存里的数据,并通知底层去进行实际的写操作。(强制把缓存区里面的数据写入到文件)
  4. close();关闭当前流,释放与该流相关的资源。

2.2 Writer类的子类:FileWriter

FileWriter类从OutputStreamWriter类继承而来(间接继承Writer类)。该类按字符向流中写入数据。

2.3 FileWriter 构造方法和常用方法

2.3.1 构造方法
  1. FileWriter(File file);通过打开一个到实际文件的连接来创建一个FileWriter,该文件通过文件系统中的 File 对象 file 指定。
  2. FileWriter(File file, boolean append);通过打开一个到实际文件的连接来创建一个FileWriter,该文件通过文件系统中的 File 对象 file 指定。 如果第二个参数为true,则将字符写入文件末尾处,而不是写入文件开始处。
  3. FileWriter(String fileName);通过打开一个到实际文件的连接来创建一个FileWriter,该文件通过文件系统中的路径名 name 指定。
  4. FileWriter(String fileName, boolean append);通过打开一个到实际文件的连接来创建一个FileWriter,该文件通过文件系统中的路径名 name 指定。如果第二个参数为true,则将字符写入文件末尾处,而不是写入文件开始处。
  5. FileWriter(FileDescriptor fd);在给定从中写入数据的FileDescriptor 的情况下创建一个新 FileReader。(可以向控制台输出文本流)。
2.3.2 常用方法
  1. write (String str); 将指定的字符串写入此输出流。

    try {
    File file = new File("test.txt");
    Writer fileWriter = new FileWriter(file);
    fileWriter.write("十年之前,我不认识你。");
    fileWriter.flush();
    fileWriter.close();
    }...
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    结果:

  2. write(int c );将指定的字符写入此输出流。

    try {
    File file = new File("test.txt");
    Writer fileWriter = new FileWriter(file);
    fileWriter.write('育');
    fileWriter.flush();
    fileWriter.close();
    }...
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    结果:

  3. write(char[] cbuf);将 cbuf 字符数组写入此输出流。

    try {
    File file = new File("test.txt");
    Writer fileWriter = new FileWriter(file);
    char[] charArray = "字符串转字符数组".toCharArray();
    fileWriter.write(charArray);
    fileWriter.flush();
    fileWriter.close();
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    结果:

  4. write(char[] cbuf, int off, int len);将 cbuf 字符数组,按偏移量 off 开始的 len 个字符写入此输出流。

    try {
    File file = new File("test.txt");
    Writer fileWriter = new FileWriter(file);
    char[] charArray = "字符串转字符数组".toCharArray();
    fileWriter.write(charArray, 1, 5);//从偏移量 1 开始,写入5个字符。
    fileWriter.flush();
    fileWriter.close();
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    结果:

  5. write(String str, int off, int len);

    try {
    File file = new File("test.txt");
    Writer fileWriter = new FileWriter(file);
    String str ="字符串也可以制定写的内容";
    fileWriter.write(str, 3, 5);
    fileWriter.flush();
    fileWriter.close();
    } 
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    结果:

3 字符缓存流(BufferedReader/BufferedWriter)

(BufferedReader/BufferedWriter) 是带缓冲区的字符流,默认缓冲区大小是8Kb,能够减少访问磁盘的次数,提高文件读取性能;并且可以一次性读取一行字符。(类似管道套管道一样,不带缓冲的流只能一滴一滴流,套了管道后,可以让一滴一滴留到外面的管道后一次性流出。)

3.1 字符缓存流构造方法

3.1.1 BufferedReader
  1. BufferedReader(Reader in);创建一个默认缓冲区大小 8Kb 的字符缓冲输入流;
  2. BufferedReader(Reader in, int sz);创建一个字符缓冲输入流;并分配 sz/byte 大小的缓冲区。
3.1.1 BufferedWriter
  1. BufferedWriter(Writer out); 创建一个默认缓冲区大小 8Kb 的字符缓冲输出流;
  2. BufferedWriter(Writer out, int sz); 创建一个字符缓冲输出流;并分配 sz/byte 大小的缓冲区。

3.2 字符缓存流的常用方法:readLine(), newLine()

  1. BufferedReader.readLine();在字符缓冲输入流读取字符的时候,可以一次性读取一行,并将游标指向下一行。

    try {
    File file = new File("test.txt");
    FileReader fr = new FileReader(file);
    BufferedReader br = new BufferedReader(fr);
    String str;
    while ((str = br.readLine())!=null) {
        System.out.println(str);
    }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  2. BufferedWriter.newLine();在字符串缓冲输出流写入字符的时候,默认是在一行写入,当需要换行的时候,调用 newLine() 实现文本换行。

    try {
    File file = new File("test.txt");
    FileWriter fw = new FileWriter(file);
    BufferedWriter bw = new BufferedWriter(fw);
    bw.write("写入一行的文本");
    bw.newLine();//换行
    bw.write("写入第二行的文本");
    bw.flush();//刷新缓冲区,强制写入文件中
    bw.close();
    }...
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

4.字节流与字符流的区别

字节流和字符流使用是非常相似的,那么除了操作代码的不同之外,还有哪些不同呢?

字节流在操作的时候本身是不会用到缓冲区(内存)的,是与文件本身直接操作的,而字符流在操作的时候是使用到缓冲区的

字节流在操作文件时,即使不关闭资源(close方法),文件也能输出,但是如果字符流不使用close方法的话,则不会输出任何内容,说明字符流用的是缓冲区,并且可以使用flush方法强制进行刷新缓冲区,这时才能在不close的情况下输出内容

那开发中究竟用字节流好还是用字符流好呢?

在所有的硬盘上保存文件或进行传输的时候都是以字节的方法进行的,包括图片也是按字节完成,而字符是只有在内存中才会形成的,所以使用字节的操作是最多的。

如果要java程序实现一个拷贝功能,应该选用字节流进行操作(可能拷贝的是图片),并且采用边读边写的方式(节省内存)。

最好在流前面加上缓冲流,为了提高性能和读取速度

课后练习

  1. 使用字符流读取一个字符文件,并把其中的所有小写字母变成大写字母,然后写入到另外一个文件中。
public static void smallTOBig(File aFile, File bFile) {
        if (aFile.exists()) {
            try (FileReader fReader = new FileReader(aFile); FileWriter fWriter = new FileWriter(bFile);) {

                char[] cbuf = new char[1024];
                int read = -1;
                while ((read = fReader.read(cbuf)) != -1) {
                    String string = new String(cbuf, 0, read);
                    String upperCase = string.toUpperCase();
                    fWriter.write(upperCase);
                }
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
        File aFile = new File("test.txt");
        File bFile = new File("a.txt");
        smallTOBig(aFile, bFile);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  1. (使用字符流实现)编写程序来实现如下功能

    1. 在D盘下创建一个目录Letter
    2. 在控制台显示下列选项:1 查看请假条 2 撰写请假条
      1. 如果用户选择2,则提示用户撰写请假条,并把撰写的内容保存位文件,存入到Letter文件夹下。
        • 格式如下:
        • 请假人:王宝强
        • 请假日期:2016年8月15日
        • 请假原因:向法院起诉马蓉离婚…..先请假一天等等
      2. 如果用户选择1,则在控制台输出请假条的内容。
public static void main(String[] args) {
        System.out.println("1 查看请假条 2 撰写请假条");
        Scanner sc = new Scanner(System.in);
        int nextInt = sc.nextInt();
        switch (nextInt) {
        case 1:
            readMessage();
            break;
        case 2:
            writeMessage();
            break;
        default:
            break;
        }

    }

    public static void readMessage() {
        try (FileReader frReader = new FileReader(new File("Letter/b.txt"));) {

            int read = -1;
            char[] cbuf = new char[1024];
            while ((read = frReader.read(cbuf)) != -1) {
                String string = new String(cbuf, 0, read);
                System.out.println(string);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    private static void writeMessage() {
        Scanner sc = new Scanner(System.in);
        System.out.println("请假人:");
        String n1 = sc.next();
        System.out.println("请假日期:");
        String n2 = sc.next();
        System.out.println("请假原因:");
        String n3 = sc.next();
        try (FileWriter fWriter = new FileWriter(new File("Letter/b.txt"));) {
            StringBuffer stringBuffer = new StringBuffer();
            fWriter.write("请假人:" + stringBuffer.append(n1));
            fWriter.write("\r\n");
            fWriter.write("请假日期:" + stringBuffer.append(n2));
            fWriter.write("\r\n");
            fWriter.write("请假原因:" + stringBuffer.append(n3));
            fWriter.write("\r\n");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  1. 写一个程序,记录程序在运行时出现过的错误,保存成错误日志!。如:追加写入:true

    • 在输入Int类型的时候输错,把这个记录写入到文件中。

    • 在String 类型 转换 int类型的时候如果出错,把错误的记录写入到文件中。

    • 格式如下:

      err:2017年3月30日 15:26:33 字符串转换Int失败 不能把 abc 转成 int 类型。

      err:2017年3月30日 15:27:12 Scanner输入类型错误,要求输入int,却输入了”xyz”。

    提示:捕获程序有可能出现错误的地方,在catch语句中 将错误的信息 用自己的语言组织,写入到File中。

public static void collectErr(File file) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入你要输入的整数值");
        try {
            int nextInt = scanner.nextInt();

        } catch (Exception e) {
            try (FileWriter fWriter = new FileWriter(file, true);) {
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat();
                Date date = new Date();
                String format = simpleDateFormat.format(date);
                fWriter.write(format + "符串转换Int失败 不能把输入的转成 int 类型" + "\r\n");
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            System.out.println("找到一次错误");
        }

    }

    public static void collect2Err(File file) {
        Scanner scanner = new Scanner(System.in);
        try {
            System.out.println("请输入你要输入的字符型值");
            String next = scanner.next();
            int parseInt = Integer.parseInt(next);
        } catch (NumberFormatException e) {
            try (FileWriter fWriter = new FileWriter(file, true);) {
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat();
                Date date = new Date();
                String format = simpleDateFormat.format(date);
                fWriter.write(format + "Scanner输入类型错误,要求输入int,却输入了xyz" + "\r\n");
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            System.out.println("又找到一次错误");
        }

    }

    public static void main(String[] args) {
        File file = new File("d.txt");
        collectErr(file);
        collect2Err(file);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号