程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • JavaIO流

    • 初识 Java IO 流
    • 文件操作
    • 字节流
    • 字符流
      • 1. 字符输入流【Reader】
      • 2. FileReader类
        • 1. 单字符读取示例
        • 2. 批量读取字符到数组
        • 3. 指定起始位置和长度读取
      • 3. 字符输出流【Writer】
      • 4. FileWriter类
        • 1. 单字符写入示例
        • 2. 写入字符数组
        • 3. 写入字符串
        • 4. 文件追加写入
        • 5. 换行操作
        • 6. 关闭和刷新
    • 缓冲流
    • 节点流和处理流的区别
    • IO流 其他内容
  • IO流
  • JavaIO流
scholar
2024-08-22
目录

字符流

# 字符流

与字节流类似,字符流也有两个抽象基类,分别是Reader和 Writer。其他的字符流实现类都是继承了这两个类。

以Reader为例,它的主要实现子类如下图:

image-20230312151354900

image-20230312151407512

当使用字节流读取文本文件时,可能会有一个小问题。就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储。所以Java提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。

小贴士

字符流,只能操作文本文件,不能操作图片,视频等非文本文件。当我们单纯读或者写文本文件时 使用字符流 其他情况使用字节流。

# 1. 字符输入流【Reader】

java.io.Reader抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。

  • public int read(): 从输入流读取一个字符。 虽然读取了一个字符,但是会自动提升为int类型。返回该字符的Unicode编码值。如果已经到达流末尾了,则返回-1。
  • public int read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。每次最多读取cbuf.length个字符。返回实际读取的字符个数。如果已经到达流末尾,没有数据可读,则返回-1。
  • public int read(char[] cbuf,int off,int len):从输入流中读取一些字符,并将它们存储到字符数组 cbuf中,从cbuf[off]开始的位置存储。每次最多读取len个字符。返回实际读取的字符个数。如果已经到达流末尾,没有数据可读,则返回-1。
  • public void close() :关闭此流并释放与此流相关联的任何系统资源。

小贴士:close方法,当完成流的操作时,必须调用此方法,释放系统资源。

# 2. FileReader类

FileReader 提供了几种构造方法,用于根据不同的需求创建读取文件的流对象。常用的构造方法包括:

  1. FileReader(String fileName):

    • 通过指定文件路径来创建 FileReader 对象。
    • 参数:fileName 是文件的路径,类型为 String。
    • 该构造方法会根据提供的路径打开文件。如果文件不存在,将抛出 FileNotFoundException。
    FileReader fr = new FileReader("e:/sort.txt");
    
    1
  2. FileReader(File file):

    • 通过指定的 File 对象来创建 FileReader 对象。
    • 参数:file 是一个 File 类型的对象。
    • 该构造方法允许我们使用一个 File 对象来指定文件,而不是直接使用字符串路径。类似地,如果文件不存在,会抛出 FileNotFoundException。
    File file = new File("e:/sort.txt");
    FileReader fr = new FileReader(file);
    
    1
    2

# 1. 单字符读取示例

  1. 创建 FileReader 对象: 指定要读取的文件路径。
  2. 逐字符读取: 使用 read() 方法逐个读取字符,直到返回 -1(文件末尾)。
  3. 关闭流: 使用 close() 方法释放资源。

代码示例:逐字符读取

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

/**
 * 示例:使用 FileReader 逐个字符读取文件内容。
 */
public class FileReaderSingleCharExample {
    public static void main(String[] args) {
        FileReader fr = null;
        try {
            // Step 1: 创建 FileReader 对象,指定文件路径
            fr = new FileReader("e:/sort.txt");
            
            int data; // 用于存储读取到的字符(Unicode 编码值)
            // Step 2: 逐个字符读取,直到文件末尾(返回 -1)
            while ((data = fr.read()) != -1) {
                // 将 Unicode 编码转换为字符并打印
                System.out.print((char) data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // Step 3: 确保流资源被正确关闭
            if (fr != null) {
                try {
                    fr.close();
                } 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

# 2. 批量读取字符到数组

  1. 创建 FileReader 对象: 指定要读取的文件路径。
  2. 创建字符数组: 用于存储读取的字符数据。
  3. 批量读取: 使用 read(char[] cbuf) 方法将多个字符读取到数组中,返回实际读取的字符数。
  4. 关闭流: 使用 close() 方法释放资源。

代码示例:批量读取字符

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

/**
 * 示例:使用 FileReader 批量读取字符到数组中。
 */
public class FileReaderCharArrayExample {
    public static void main(String[] args) {
        FileReader fr = null;
        try {
            // Step 1: 创建 FileReader 对象,指定文件路径
            fr = new FileReader("e:/sort.txt");

            // Step 2: 创建字符数组作为缓冲区
            char[] buffer = new char[1024];
            int len; // 每次读取的字符数

            // Step 3: 批量读取字符到数组,直到文件末尾(返回 -1)
            while ((len = fr.read(buffer)) != -1) {
                // 将读取的字符数组转换为字符串并打印,只打印实际读取的部分
                System.out.print(new String(buffer, 0, len));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // Step 4: 确保流资源被正确关闭
            if (fr != null) {
                try {
                    fr.close();
                } 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

# 3. 指定起始位置和长度读取

  1. 创建 FileReader 对象: 指定要读取的文件路径。
  2. 创建字符数组: 用于存储读取的字符数据。
  3. 指定读取位置和长度: 使用 read(char[] cbuf, int off, int len) 方法从指定位置开始读取指定长度的字符数据。
  4. 关闭流: 使用 close() 方法释放资源。

代码示例:指定位置和长度读取

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

/**
 * 示例:使用 FileReader 从指定位置和长度读取字符数据。
 */
public class FileReaderSpecificPositionExample {
    public static void main(String[] args) {
        FileReader fr = null;
        try {
            // Step 1: 创建 FileReader 对象,指定文件路径
            fr = new FileReader("e:/sort.txt");

            // Step 2: 创建字符数组作为缓冲区
            char[] buffer = new char[1024];

            // Step 3: 从字符数组的指定位置开始,读取固定长度的字符
            int len = fr.read(buffer, 0, 10); // 从 buffer[0] 开始读取 10 个字符

            // 将读取的字符数组转换为字符串并打印
            System.out.print(new String(buffer, 0, len));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // Step 4: 确保流资源被正确关闭
            if (fr != null) {
                try {
                    fr.close();
                } 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

总结

  • Reader 是字符输入流的基类,提供了读取字符的基础方法。
  • FileReader 是用于从文件中读取字符数据的具体实现类,适合读取文本文件。
  • 逐字符读取适合处理小数据量或逐步解析的场景,批量读取则适合处理大文件或需要提高效率的场景。
  • 在操作完流后,务必调用 close() 方法以释放系统资源,避免资源泄露。

# 3. 字符输出流【Writer】

java.io.Writer抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字节输出流的基本共性功能方法。

  • public void write(int c) 写入单个字符。
  • public void write(char[] cbuf)写入字符数组。
  • public void write(char[] cbuf, int off, int len)写入字符数组的某一部分,off是数组的开始索引,len是写的字符个数。
  • public void write(String str)写入字符串。
  • public void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
  • public void flush()刷新该流的缓冲。
  • public void close() 关闭此流,但要先刷新它。

# 4. FileWriter类

java.io.FileWriter类是写出字符到文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。

  • FileWriter(File file): 创建一个新的 FileWriter,给定要读取的File对象。
  • FileWriter(String fileName): 创建一个新的 FileWriter,给定要读取的文件的名称。

当你创建一个流对象时,必须传入一个文件路径,类似于FischolarutputStream。如果文件不存在,则会自动创建。如果文件已经存在,则会清空文件内容,写入新的内容。

# 1. 单字符写入示例

  1. 创建 FileWriter 对象: 指定要写入的文件路径。
  2. 写入单个字符: 使用 write(int c) 方法写入字符数据。
  3. 关闭流: 使用 close() 方法释放资源。

代码示例:写入单个字符

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

/**
 * 示例:使用 FileWriter 写入单个字符到文件中。
 */
public class FileWriterSingleCharExample {
    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            // Step 1: 创建 FileWriter 对象,指定文件路径
            fw = new FileWriter("fw.txt");

            // Step 2: 写入单个字符
            fw.write(97);  // 写入字符 'a'
            fw.write('b'); // 写入字符 'b'
            fw.write('C'); // 写入字符 'C'
            fw.write(30000); // 写入字符对应的 Unicode 码点为 30000 的字符

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // Step 3: 关闭流,确保数据完全写入文件
            if (fw != null) {
                try {
                    fw.close();
                } 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

# 2. 写入字符数组

  1. 创建 FileWriter 对象: 指定要写入的文件路径。
  2. 写入字符数组: 使用 write(char[] cbuf) 方法写入整个字符数组或部分数据。
  3. 关闭流: 使用 close() 方法释放资源。

代码示例:写入字符数组

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

/**
 * 示例:使用 FileWriter 写入字符数组到文件中。
 */
public class FileWriterCharArrayExample {
    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            // Step 1: 创建 FileWriter 对象,指定文件路径
            fw = new FileWriter("fw.txt");

            // Step 2: 写入字符数组
            char[] chars = "程序员scholar".toCharArray();
            fw.write(chars); // 写入整个字符数组

            // Step 3: 写入字符数组的一部分
            fw.write(chars, 1, 2); // 从索引 1 开始,写入 2 个字符

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // Step 4: 关闭流,确保数据完全写入文件
            if (fw != null) {
                try {
                    fw.close();
                } 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

# 3. 写入字符串

  1. 创建 FileWriter 对象: 指定要写入的文件路径。
  2. 写入字符串: 使用 write(String str) 方法写入整个字符串或部分数据。
  3. 关闭流: 使用 close() 方法释放资源。

代码示例:写入字符串

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

/**
 * 示例:使用 FileWriter 写入字符串到文件中。
 */
public class FileWriterStringExample {
    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            // Step 1: 创建 FileWriter 对象,指定文件路径
            fw = new FileWriter("fw.txt");

            // Step 2: 写入字符串
            String msg = "程序员scholar";
            fw.write(msg); // 写入整个字符串

            // Step 3: 写入字符串的一部分
            fw.write(msg, 1, 2); // 从索引 1 开始,写入 2 个字符

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // Step 4: 关闭流,确保数据完全写入文件
            if (fw != null) {
                try {
                    fw.close();
                } 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

# 4. 文件追加写入

FileWriter类提供了两种构造方法来支持文件的续写,即在文件的末尾追加内容而不是覆盖原始内容。

  • public FileWriter(File file,boolean append): 创建文件输出流以写入由指定的 File对象表示的文件。
  • public FileWriter(String fileName,boolean append): 创建文件输出流以指定的名称写入文件。

这两个构造方法,参数中都需要传入一个boolean类型的值,true 表示追加数据,false 表示清空原有数据。这样创建的输出流对象,就可以指定是否追加续写了,代码使用演示:

操作类似于FileOutputStream。

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

/**
 * 示例:使用 FileWriter 进行文件追加写入。
 */
public class FileWriterAppendExample {
    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            // Step 1: 创建 FileWriter 对象,设置 append 为 true 开启追加模式
            fw = new FileWriter("fw.txt", true);

            // Step 2: 写入数据,将数据追加到文件末尾
            fw.write("程序员scholar真棒");

            // 输出提示信息,表明数据已成功追加写入
            System.out.println("数据追加写入完成!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // Step 3: 关闭流,确保数据完全写入文件
            if (fw != null) {
                try {
                    fw.close();
                } 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

# 5. 换行操作

在使用FileWriter类写入文件时,有时需要在写入的字符串之间添加换行符以实现换行。这可以通过写入系统相关的换行符来完成。在Windows系统中,换行符为\r\n;在Linux和Unix系统中,换行符为\n;而在Mac系统中(旧版本),换行符为\r。为了跨平台兼容性,建议使用System.getProperty("line.separator")来获取系统的换行符。

以下示例展示了如何使用FileWriter类进行写入操作,并在两段字符串之间添加换行符以实现换行:

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

/**
 * 示例:使用 FileWriter 写入数据并添加换行符。
 */
public class FileWriterNewLineExample {
    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            // Step 1: 创建 FileWriter 对象,指定文件路径
            fw = new FileWriter("fw.txt");

            // Step 2: 写入数据并添加换行符
            fw.write("程序员scholar");
            fw.write(System.getProperty("line.separator")); // 添加系统相关的换行符

            // 再次写入数据
            fw.write("再次欢迎程序员scholar");

            System.out.println("数据写入完成,并正确换行。");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // Step 3: 关闭流,确保数据完全写入文件
            if (fw != null) {
                try {
                    fw.close();
                } 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

# 6. 关闭和刷新

【注意】FileWriter与FileOutputStream不同。因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要flush 方法了。

  • flush :刷新缓冲区,流对象可以继续使用。
  • close:先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。

代码使用演示:

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

/**
 * 示例:使用 FileWriter 进行数据的刷新与关闭操作。
 */
public class FileWriterFlushExample {
    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            // Step 1: 创建 FileWriter 对象,指定文件路径
            fw = new FileWriter("fw.txt");

            // Step 2: 写出数据并演示 flush 方法
            fw.write('刷'); // 写出字符
            fw.flush(); // 刷新缓冲区,确保数据写入文件

            fw.write('新'); // 继续写出字符,流仍然可用
            fw.flush(); // 再次刷新

            fw.write('关'); // 写出字符
            fw.close(); // 关闭流,释放资源

            // 尝试在流关闭后写出数据,这会引发 IOException
            fw.write('闭'); // 抛出 IOException,因为流已经关闭
        } catch (IOException e) {
            System.out.println("发生异常:" + e.getMessage());
        } finally {
            // 确保流在出现异常时被正确关闭
            if (fw != null) {
                try {
                    fw.close(); // 再次尝试关闭流
                } 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

小贴士:即便是flush方法写出了数据,操作的最后还是要调用close方法,释放系统资源。

编辑此页 (opens new window)
上次更新: 2024/12/28, 18:32:08
字节流
缓冲流

← 字节流 缓冲流→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式