Java 字符流详解

在 Java 的 I/O 体系中,字符流(ReaderWriter)是专门用于处理文本数据的输入输出流。与字节流不同,字符流以字符为单位进行读取和写入,能够更好地处理文本信息,尤其是包含多字节字符(如中文)的文本文件。本文将从字符流的类关系图开始,详细介绍字符流的原理、使用方法以及常见问题。
在这里插入图片描述

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

字节流(InputStreamOutputStream)以字节为单位进行读写,适用于处理二进制数据(如图片、音频、视频等)。而字符流(ReaderWriter)以字符为单位进行读写,适用于处理文本数据。

示例:字节流读取中文乱码问题

/**
* 中文乱码问题
* @throws IOException
*/
private static void testChineseCharacterEncode() throws IOException {//FileInputStream为操作文件的字符输入流FileInputStream inputStream = new FileInputStream("JavaSE/resourses/a.txt");//内容为“沉默王二是傻 X”int len;while ((len=inputStream.read())!=-1){System.out.print((char)len);}
}

运行结果:

沉默王二是傻 X

出现乱码的原因是字节流无法正确处理多字节字符的编码问题。为了解决这个问题,可以使用字符流或者在字节流的基础上进行编码转换。

示例:字节流正确读取中文

/**
* 字节流正确读取中文
* @throws IOException
*/
private static void testCharacterCharacterEncode2() throws IOException {try (FileInputStream inputStream = new FileInputStream("JavaSE/resourses/a.txt")) {byte[] bytes = new byte[1024];int len;while ((len = inputStream.read(bytes)) != -1) {System.out.print(new String(bytes, 0, len));}}
}

通过 new String(byte bytes[], int offset, int length) 构造方法,Java 会根据默认的 UTF-8 编码将字节流转换为字符串,从而正确解码中文字符。

public String(byte bytes[], int offset, int length) {checkBounds(bytes, offset, length);this.value = StringCoding.decode(bytes, offset, length);
}

继续追看 StringCoding.decode() 方法调用的 defaultCharset() 方法,会发现默认编码是UTF-8,代码如下

public static Charset defaultCharset() {if (defaultCharset == null) {synchronized (Charset.class) {if (cs != null)defaultCharset = cs;elsedefaultCharset = forName("UTF-8");}}return defaultCharset;
}
static char[] decode(byte[] ba, int off, int len) {String csn = Charset.defaultCharset().name();try {// use charset name decode() variant which provides caching.return decode(csn, ba, off, len);} catch (UnsupportedEncodingException x) {warnUnsupportedCharset(csn);}
}

2. 字符流的基本概念

字符流 = 字节流 + 编码表

字符流的核心思想是将字节流与字符编码表结合起来,通过编码表将字节数据转换为字符数据。常见的字符编码包括 ASCII、ISO-8859-1、UTF-8、UTF-16 等。

3. 字符输入流(Reader)

java.io.Reader 是字符输入流的超类,定义了字符输入流的一些共性方法:

  • close():关闭流并释放相关资源。
  • read():读取一个字符。
  • read(char[] cbuf):读取多个字符并存储到字符数组中。

FileReader 是 Reader 的子类,用于从文件中读取字符数据。它的主要特点如下:

  • 可以通过构造方法指定要读取的文件路径。
  • 每次可以读取一个或多个字符。
  • 可以读取 Unicode 字符集中的字符,通过指定字符编码来实现字符集的转换。

3.1 FileReader构造方法

  • FileReader(File file):创建一个新的 FileReader,参数为File对象。
  • FileReader(String fileName):创建一个新的 FileReader,参数为文件名。
// 使用File对象创建流对象
File file = new File("a.txt");
FileReader fr = new FileReader(file);// 使用文件名称创建流对象
FileReader fr = new FileReader("b.txt");

3.2 FileReader读取字符数据

  • 读取字符read方法,每次可以读取一个字符,返回读取的字符(转为 int 类型),当读取到文件末尾时,返回-1
FileReader fr = new FileReader("abc.txt");
int b;
while ((b = fr.read()) != -1) {System.out.println((char) b);
}
fr.close();
  • 读取指定长度的字符read(char[] cbuf, int off, int len),并将其存储到字符数组中。其中,cbuf 表示存储读取结果的字符数组,off 表示存储结果的起始位置,len 表示要读取的字符数。
File textFile = new File("docs/约定.md");
try (FileReader reader = new FileReader(textFile)) {char[] buffer = new char[1024];int len;while ((len = reader.read(buffer, 0, buffer.length)) != -1) {System.out.print(new String(buffer, 0, len));}
}

4. 字符输出流(Writer)

java.io.Writer 是字符输出流的超类,定义了字符输出流的一些共性方法:

  • write(int c):写入单个字符。
  • write(char[] cbuf):写入字符数组。
  • write(char[] cbuf, int off, int len):写入字符数组的一部分。
  • write(String str):写入字符串。
  • write(String str, int off, int len):写入字符串的一部分。
  • flush():刷新缓冲区。
  • close():关闭流并刷新缓冲区。

FileWriter 是 Writer 的子类,用于将字符写入文件。

4.1 FileWriter构造方法

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

4.2 FileWriter写入数据

  • 写入字符write(int b) 方法,每次可以写出一个字符
FileWriter fw = new FileWriter("output.txt");
fw.write(72); // 写入字符'H'的ASCII码
fw.write(101); // 写入字符'e'的ASCII码
fw.write(108); // 写入字符'l'的ASCII码
fw.write(108); // 写入字符'l'的ASCII码
fw.write(111); // 写入字符'o'的ASCII码
fw.close();
  • 写入字符数组write(char[] cbuf) 方法,将指定字符数组写入输出流。
FileWriter fw = new FileWriter("output.txt");
char[] chars = {'H', 'e', 'l', 'l', 'o'};
fw.write(chars); // 将字符数组写入文件
fw.close();
  • 写入指定字符数组write(char[] cbuf, int off, int len) 方法,将指定字符数组的一部分写入输出流。
fw = new FileWriter("output.txt");char[] chars = {'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!'};
fw.write(chars, 0, 5); // 将字符数组的前 5 个字符写入文件
  • 写入字符串write(String str) 方法,将指定字符串写入输出流。
FileWriter fw = new FileWriter("output.txt");
String str = "沉默王二";
fw.write(str); // 将字符串写入文件
fw.close();
  • 写入指定字符串write(String str, int off, int len) 方法,将指定字符串的一部分写入输出流。
String str = "沉默王二真的帅啊!";
try (FileWriter fw = new FileWriter("output.txt")) {fw.write(str, 0, 5); // 将字符串的前 5 个字符写入文件
} catch (IOException e) {e.printStackTrace();
}

5. 关闭与刷新

  • flush():刷新缓冲区,流对象可以继续使用。
  • close():先刷新缓冲区,然后通知系统释放资源,流对象不可以再被使用。
FileWriter fw = new FileWriter("fw.txt");
fw.write('刷'); // 写出第1个字符
fw.flush();
fw.write('新'); // 继续写出第2个字符,写出成功
fw.close();

6. 续写与换行

续写和换行:操作类似于FileOutputStream操作,直接上代码:

// 使用文件名称创建流对象,可以续写数据
FileWriter fw = new FileWriter("JavaSE/resourses/fw.txt",true);
// 写出字符串
fw.write("沉默王二");
// 写出换行
fw.write("\r\n");
// 写出字符串
fw.write("是傻 X");
// 关闭资源
fw.close();

7. 文本文件复制

示例:使用 FileReader 和 FileWriter 复制文本文件

public class CopyFile {public static void main(String[] args) throws IOException {//创建输入流对象FileReader fr = new FileReader("JavaSE/resourses/a.txt");//创建输出流对象FileWriter fw = new FileWriter("JavaSE/resourses/copyaa.txt");/*创建输出流做的工作:*      1、调用系统资源创建了一个文件*      2、创建输出流对象*      3、把输出流对象指向文件* *///文本文件复制,一次读一个字符// copyMethod1(fr,fw);//文本文件复制,一次读一个字符数组copyMethod2(fr,fw);fr.close();fw.close();}/*** 文本文件复制,一次读一个字符* @param fr* @param fw* @throws IOException*/private static void copyMethod1(FileReader fr, FileWriter fw) throws IOException {int ch;while ((ch = fr.read()) != -1) {//读数据fw.write(ch);//写数据}fw.flush();}/*** 文本文件复制,一次读一个字符数组* @param fr* @param fw* @throws IOException*/private static void copyMethod2(FileReader fr, FileWriter fw) throws IOException {char[] chs = new char[1024];int len = 0;while ((len = fr.read(chs)) != -1) {//读数据fw.write(chs,0,len);//写数据}fw.flush();}
}

8. IO 异常处理

在实际开发中,建议使用 try...catch...finally 代码块处理异常,确保资源能够正确关闭。或者直接使用 try-with-resources 的方式。
示例:使用try…catch…finally 代码块处理异常

 // 声明变量FileWriter fw = null;try {//创建流对象fw = new FileWriter("JavaSE/resourses/fw.txt");// 写出数据fw.write("二哥真的帅");} catch (IOException e) {e.printStackTrace();} finally {try {if (fw != null) {fw.close();}} catch (IOException e) {e.printStackTrace();}}

示例:使用 try-with-resources 处理异常

try (FileWriter fw = new FileWriter("fw.txt")) {fw.write("二哥真的帅");
} catch (IOException e) {e.printStackTrace();
}

9. 小结

字符流(Reader 和 Writer)是 Java I/O 中用于处理文本数据的抽象类。通过字符流,可以更方便地读取和写入字符数据,避免了字节流在处理多字节字符时的编码问题。常见的字符流子类包括 FileReader 和 FileWriter,它们分别用于从文件中读取和写入字符数据。在使用字符流时,需要注意字符编码的问题,并确保在操作完成后正确关闭流对象。

10.思维导图

在这里插入图片描述

11.参考链接

Java 字符流:Reader和Writer的故事

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/461779.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux 多线程编程

韦东山的例程所谓线程,就是操作系统所能调度的最小单位。普通的进程,只有一个线程在执行对应的逻辑。我们可以通过多线程编程,使一个进程可以去执行多个不同的任务。相比多进程编程而言,线程享有共享资源,即在进程中出…

后端:Spring-1

文章目录 1. 了解 spring(Spring Framework)2. 基于maven搭建Spring框架2.1 纯xml配置方式来实现Spring2.2 注解方式来实现Spring3. Java Config类来实现Spring 2.4 总结 1. 了解 spring(Spring Framework) 传统方式构建spring(指的是Spring Framework)项目,导入依…

【C++动态规划 01背包】2787. 将一个数字表示成幂的和的方案数

本文涉及知识点 C动态规划 C背包问题 LeetCode2787. 将一个数字表示成幂的和的方案数 给你两个 正 整数 n 和 x 。 请你返回将 n 表示成一些 互不相同 正整数的 x 次幂之和的方案数。换句话说,你需要返回互不相同整数 [n1, n2, …, nk] 的集合数目,满…

Python爬虫的京东大冒险:如何高效获取商品详情的秘籍

在这个由代码编织的电商世界里,京东商品详情就像是被锁在高塔中的公主,等待着勇敢的Python爬虫骑士去解救。今天,我们要讲述的是如何成为一名Python爬虫骑士,携带你的代码长矛,穿梭在API的数据森林中,高效获…

SpringBoot【实用篇】- 测试

文章目录 目标:1.加载测试专用属性3.Web环境模拟测试2.加载测试专用配置4.数据层测试回滚5.测试用例数据设定 目标: 加载测试专用属性加载测试专用配置Web环境模拟测试数据层测试回滚测试用例数据设定 1.加载测试专用属性 我们在前面讲配置高级的时候…

vfx特效有多烧钱?云渲染农场减少vfx特效成本

特效制作一直是电影制作中的烧钱大户,尤其是视觉特效(VFX)的高昂成本让许多项目望而却步。但随着云渲染农场技术的发展,VFX特效的成本得到了有效控制,为电影工业带来了革命性的变化。 在电影工业中,VFX特效…

任何python安装gdal出现的问题

Releases cgohlke/geospatial-wheels GitHubGeospatial library wheels for Python on Windows. Contribute to cgohlke/geospatial-wheels development by creating an account on GitHub.https://github.com/cgohlke/geospatial-wheels/releases 各种乱七八糟的gdal库问题…

tensorflow案例4--人脸识别(损失函数选取,调用VGG16模型以及改进写法)

🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 前言 这个模型结构算上之前的pytorch版本的,算是花了不少时间,但是效果一直没有达到理想情况,主要是验证集和训练集准确率…

SPA和SSR

单页面应用程序(SPA) 单页面应用(SPA)全称是:Single-page application, SPA应用是在客户端呈现的(术语称:CRS)。 SPA应用默认只返回一个空HTML页面&#xff0c;如:body只有<div id"app"></div>而整个应用程序的内容都是通过JavaScript动态加载&#xf…

【 纷享销客-注册安全分析报告-无验证方式导致安全隐患】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…

基于SpringBoot和PostGIS的世界各国邻国可视化实践

目录 前言 一、空间数据查询基础 1、空间数据库基础 2、空间相邻查询 二、SpringBoot后台功能设计 1、后台查询接口的实现 2、业务接口设计 三、Leaflet进行WebGIS开发 1、整体结构介绍 2、相邻国家展示可视化 四、成果展示 1、印度及其邻国 2、乌克兰及其邻国 3、…

Python之groupby()及aggregate()方法

目录 数据准备df.describe()思考1 分组 pd.groupby()思考2 df.aggregate()思考1 现在有一份titanic_train.csv&#xff0c;包含泰坦尼克号乘客信息及获救情况的明细数据&#xff0c;我们需要使用一些聚合函数&#xff0c;统计相关指标。 数据准备 import pandas as pd df pd.…

Unity 二次元三渲二

三渲二 注意&#xff1a;Unity必须是2022.3LTS及以上和URP项目&#xff01;&#xff01;&#xff01; 下载三渲二插件 【如何将原神的角色导入Unity】全网最细致教程&#xff0c;全程干货。不使用任何收费插件&#xff0c;使用Spring Bone对头发和衣服进行物理模拟。_原神 步…

Unity计算二维向量夹角余弦值和正弦值的优化方法参考

如果不考虑优化问题&#xff0c;计算两个向量的余弦值或者正弦值可以直接使用类似的方法&#xff1a; [SerializeField] Vector2 v1, v2;void Start() {float valCos Mathf.Acos(Vector2.SignedAngle(v1, v2));float valSin Mathf.Asin(Vector2.SignedAngle(v1, v2)); } 但是…

深度|谁在为OpenAI和Anthropic的AI编程竞赛提供“军火”?已赚得盆满钵满

图片来源&#xff1a;Unsplash AI 开发者之所以一致认为编程的重要性&#xff0c;是有原因的&#xff1a;大型语言模型编程能力越强&#xff0c;它回答与软件无关的其他类型问题的能力也越强。 去年秋天&#xff0c;几位 Google 人工智能领导者与初创公司 CEO Jonathan Siddh…

2024年北京市安全员-A证证模拟考试题库及北京市安全员-A证理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年北京市安全员-A证证模拟考试题库及北京市安全员-A证理论考试试题是由安全生产模拟考试一点通提供&#xff0c;北京市安全员-A证证模拟考试题库是根据北京市安全员-A证最新版教材&#xff0c;北京市安全员-A证大…

[ 问题解决篇 ] win11中本地组策略编辑器gpedit.msc打不开(gpedit.msc缺失)

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

前端聊天室页面开发(赛博朋克科技风,内含源码)

肝了一天&#xff0c;经过各种处理美化&#xff0c;肝出来了一个赛博朋克科技风的前端页面&#xff0c;用的原生三件套htmlcssjavascript开发的&#xff0c;本来想是加点功能调用一下gpt接口&#xff0c;但是基本都需要webscoket通信&#xff0c;可惜我js学的不是很深入&#x…

TMDOG的Gin学习笔记_01——初识Gin框架

TMDOG的Gin学习笔记_01——初识Gin框架 博客地址&#xff1a;[TMDOG的博客](https://blog.tmdog114514.icu) 作者自述&#xff1a; 停更太久了&#xff0c;是因为开学了课太多了&#xff0c;并且我一直在准备上篇文章的内容正在coding&#xff0c;就先搁置了更新博客QAQ&…

wsl2.0(windows linux子系统)使用流程

1.什么是wsl wsl指的是windows的linux子系统&#xff0c;最初是wsl1.0&#xff0c;靠windows内核来模拟linux内核&#xff0c;并不运行真正的linux内核&#xff0c;所以有时会有兼容性的问题。 而wsl2.0是基于windows自带的虚拟机功能hyper-v的&#xff0c;它会把设备上的每个…