news 2026/7/15 2:43:49

吃透Java IO!从字节流到字符流,一篇讲明白

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
吃透Java IO!从字节流到字符流,一篇讲明白

作为Java程序员,不管是读写文件、处理网络数据,还是操作控制台输入输出,IO 都是绕不开的坎。刚学的时候,看着 InputStream、OutputStream、Reader、Writer 一堆类,属实有点头大。今天就用大白话,把Java IO的核心知识点捋清楚,新手也能轻松看懂!

一、先搞懂:Java IO到底是啥?

IO,全称 Input/Output,翻译过来就是输入和输出。说白了,就是程序和外部设备之间的数据传输。

比如你用Java程序读取本地的txt文件,这就是输入(Input) —— 数据从文件进到程序里;你把程序里的用户信息写入到数据库,或者保存成一个新文件,这就是输出(Output) —— 数据从程序跑到外部存储里。

Java把这些IO操作都封装在了 java.io 包下,后来又出了 java.nio (NIO是Non-blocking IO,非阻塞IO,今天先聊传统IO)。核心思路就是用流的方式处理数据,这“流”就像水管,数据就是水管里的水,顺着水管就能从一端流到另一端。

二、核心分类:字节流 vs 字符流

Java IO最核心的划分,就是字节流和字符流。这俩的区别,直接决定了你该用哪个类干活。

2.1 字节流:处理一切数据的“万能选手”

字节流的操作单位是 字节(byte),1个字节等于8位。不管是文本文件、图片、音频、视频,本质上都是字节组成的,所以字节流能处理任何类型的数据。

字节流的顶级父类是两个抽象类:

- InputStream:所有字节输入流的爹,负责读数据

- OutputStream:所有字节输出流的爹,负责写数据

我们常用的是它们的子类,比如操作文件的 FileInputStream 和 FileOutputStream。

举个简单的例子:用字节流复制一张图片

java

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

public class ByteStreamDemo {

public static void main(String[] args) {

// 源文件路径和目标文件路径

String srcPath = "D:/test.jpg";

String destPath = "D:/test_copy.jpg";

// 声明流对象

FileInputStream fis = null;

FileOutputStream fos = null;

try {

// 创建流对象

fis = new FileInputStream(srcPath);

fos = new FileOutputStream(destPath);

// 定义缓冲区,每次读1024字节,提高效率

byte[] buffer = new byte[1024];

int len; // 记录每次实际读取的字节数

// 循环读取:读到末尾时,fis.read()会返回-1

while ((len = fis.read(buffer)) != -1) {

// 把读到的字节写入目标文件

fos.write(buffer, 0, len);

}

System.out.println("图片复制成功!");

} catch (IOException e) {

e.printStackTrace();

} finally {

// 关闭流,释放资源,顺序是先开后关

try {

if (fos != null) fos.close();

if (fis != null) fis.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

这里要注意两个点:一是一定要用 finally 关闭流,不然会浪费系统资源;二是用字节数组当缓冲区,比一次读一个字节快太多了!

2.2 字符流:处理文本的“专业选手”

字符流的操作单位是 字符(char),它是为了处理文本数据而生的。因为不同的编码格式(比如UTF-8、GBK),一个字符对应的字节数不一样,字符流会帮我们自动处理编码问题,避免出现乱码。

字符流的顶级父类也是两个抽象类:

- Reader:所有字符输入流的爹,负责读文本

- Writer:所有字符输出流的爹,负责写文本

常用子类比如 FileReader 和 FileWriter,直接用来读写文本文件超方便。

同样举个例子:用字符流读取txt文件内容

java

import java.io.FileReader;

import java.io.IOException;

public class CharStreamDemo {

public static void main(String[] args) {

String filePath = "D:/test.txt";

FileReader fr = null;

try {

fr = new FileReader(filePath);

char[] buffer = new char[1024];

int len;

while ((len = fr.read(buffer)) != -1) {

// 把字符数组转成字符串输出

System.out.print(new String(buffer, 0, len));

}

} catch (IOException e) {

e.printStackTrace();

} finally {

try {

if (fr != null) fr.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

这里要注意:字符流不能处理图片、音频等二进制文件,强行用的话,文件会损坏!

三、进阶技巧:缓冲流,让IO速度飞起来

刚才的例子里,我们自己定义了字节数组/字符数组当缓冲区,但Java其实给我们提供了更方便的缓冲流,它的底层就是自带了缓冲区,能大大减少磁盘的读写次数,提升效率。

缓冲流分为字节缓冲流和字符缓冲流:

- 字节缓冲流: BufferedInputStream 、 BufferedOutputStream

- 字符缓冲流: BufferedReader 、 BufferedWriter

尤其是字符缓冲流,还提供了 readLine() (按行读)和 newLine() (换行)方法,处理文本简直不要太爽!

举个字符缓冲流的例子:按行读取文本并写入新文件

java

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.FileReader;

import java.io.FileWriter;

import java.io.IOException;

public class BufferedStreamDemo {

public static void main(String[] args) {

String srcPath = "D:/source.txt";

String destPath = "D:/dest.txt";

BufferedReader br = null;

BufferedWriter bw = null;

try {

br = new BufferedReader(new FileReader(srcPath));

bw = new BufferedWriter(new FileWriter(destPath));

String line;

// 按行读取,读到末尾返回null

while ((line = br.readLine()) != null) {

bw.write(line);

bw.newLine(); // 写入换行符,不然所有内容会挤在一行

}

System.out.println("文本复制完成!");

} catch (IOException e) {

e.printStackTrace();

} finally {

try {

if (bw != null) bw.close();

if (br != null) br.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

四、必踩的坑:这些注意事项要记牢

1. 流一定要关闭:不管是手动关还是用try-with-resources语法(JDK7及以上支持),不关闭流会导致资源泄漏。try-with-resources会自动关闭流,推荐使用!

java

// try-with-resources语法,流对象写在try的括号里

try (FileInputStream fis = new FileInputStream("test.jpg");

FileOutputStream fos = new FileOutputStream("test_copy.jpg")) {

// 读写操作

} catch (IOException e) {

e.printStackTrace();

}

2. 区分绝对路径和相对路径:绝对路径是从盘符开始的完整路径(比如D:/test.txt),相对路径是相对于项目根目录的路径(比如src/test.txt),别搞混了导致文件找不到。

3. 处理编码问题:如果用字符流读写出现乱码,可以指定编码格式,比如用 InputStreamReader 包装字节流:

java

BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("test.txt"), "UTF-8"));

4. 字节流和字符流别混用:比如用FileOutputStream写文本,再用FileReader读,很容易出现乱码。

五、总结

Java IO其实没那么复杂,记住核心逻辑就行:

- 按数据类型分:字节流处理一切数据,字符流专门处理文本

- 按功能分:节点流(直接操作文件/设备,比如FileInputStream)和处理流(包装节点流,比如BufferedInputStream,提升性能)

- 关键操作:打开流→读写数据→关闭流

掌握这些基础,再去学NIO、NIO2就会轻松很多。希望这篇文章能帮到正在啃Java IO的小伙伴们,祝大家编程愉快!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/14 15:20:17

DTLN实时降噪技术:用AI算法打造纯净语音体验的完整指南

DTLN实时降噪技术:用AI算法打造纯净语音体验的完整指南 【免费下载链接】DTLN 项目地址: https://gitcode.com/gh_mirrors/dt/DTLN 在视频会议、语音通话成为日常的今天,背景噪音问题困扰着无数用户。DTLN(双信号变换LSTM网络&#x…

作者头像 李华
网站建设 2026/7/15 0:20:06

移动端视频录制技术革新:基于MediaRecorder的高性能解决方案

移动端视频录制技术革新:基于MediaRecorder的高性能解决方案 【免费下载链接】WeiXinRecordedDemo 仿微信视频拍摄UI, 基于ffmpeg的视频录制编辑 项目地址: https://gitcode.com/gh_mirrors/we/WeiXinRecordedDemo 问题场景:为什么你的视频录制总…

作者头像 李华
网站建设 2026/7/15 13:35:59

EmotiVoice与RVC的区别是什么?一文讲清两者定位差异

EmotiVoice与RVC的区别是什么?一文讲清两者定位差异 在AI语音技术飞速发展的今天,我们经常看到“声音克隆”“情感合成”“变声翻唱”等关键词频繁出现。尤其是像 EmotiVoice 和 RVC(Retrieval-based Voice Conversion) 这类开源项…

作者头像 李华
网站建设 2026/7/15 5:45:04

EmotiVoice语音合成中断怎么办?常见错误排查

EmotiVoice语音合成中断怎么办?常见错误排查 在构建智能语音助手、有声读物平台或游戏NPC对话系统时,开发者越来越倾向于使用高表现力的TTS模型来提升交互的真实感。EmotiVoice作为一款支持零样本声音克隆和多情感语音合成的开源引擎,凭借其出…

作者头像 李华
网站建设 2026/7/14 14:45:16

ComfyUI-SeedVR2视频超分插件完整安装与配置指南

ComfyUI-SeedVR2视频超分插件完整安装与配置指南 【免费下载链接】ComfyUI-SeedVR2_VideoUpscaler Non-Official SeedVR2 Vudeo Upscaler for ComfyUI 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-SeedVR2_VideoUpscaler 想要将低分辨率视频一键升级到4K画质&…

作者头像 李华
网站建设 2026/7/15 3:32:59

开源TTS新星崛起:EmotiVoice为何备受开发者青睐?

开源TTS新星崛起:EmotiVoice为何备受开发者青睐? 在虚拟主播直播中突然情绪高涨,在有声书朗读里语气随情节起伏,在游戏NPC对话时因情境变化而或怒或惧——这些曾属于真人配音的细腻表达,如今正被一个开源项目悄然实现。…

作者头像 李华