Java IO 实战学习指南:从基础到进阶(附代码实操)
Java IO 实战学习指南:从基础到进阶(附代码实操)
Java IO(输入/输出)是Java开发的核心基础,负责程序与外部设备(文件、网络、键盘等)的数据交互。很多初学者觉得IO类繁多、流概念抽象,其实掌握“先理解模型,再分场景实操”的思路就能快速上手。本文从核心概念到实战案例,带你一步步学会Java IO编程。
一、先搞懂3个核心前提(避免踩坑)
在写代码前,必须明确IO的核心逻辑,否则容易陷入“流用错、资源漏”的坑:
- IO的核心是“流”:数据像水流一样从源头(输入流)流向目的地(输出流),不可回退(除非用缓冲流);
- 按数据类型分2大类:
- 字节流(
InputStream/OutputStream):处理所有数据(图片、视频、文本等),最小单位是字节(1byte=8bit); - 字符流(
Reader/Writer):仅处理文本数据(.txt、.java等),最小单位是字符(依赖编码,如UTF-8中1个中文=3字节);
- 字节流(
- 资源必须关闭:IO流是“稀缺资源”,不用时必须关闭,否则会导致文件占用、内存泄露(推荐用Java 7+的
try-with-resources自动关闭)。
二、入门实操:从最常用的“文件IO”开始
文件操作是IO最基础的场景,先掌握字节流和字符流的文件读写,再扩展到其他场景。
场景1:字节流读写文件(万能场景,推荐优先掌握)
适合读写任意文件(文本、图片、视频等),核心类:FileInputStream(读)、FileOutputStream(写)。
案例1:读取文件内容(字节流)
需求:读取本地test.txt文件的内容,打印到控制台。
import java.io.FileInputStream;
import java.io.IOException;
public class FileByteReadDemo {
public static void main(String[] args) {
// 关键:用try-with-resources声明流,自动关闭(无需手动close())
try (FileInputStream fis = new FileInputStream("test.txt")) {
byte[] buffer = new byte[1024]; // 缓冲区(一次读1024字节,提升效率)
int len; // 记录每次实际读取的字节数
// 循环读取:read()返回-1表示读取完毕
while ((len = fis.read(buffer)) != -1) {
// 字节数组转字符串(注意编码一致,避免乱码)
String content = new String(buffer, 0, len, "UTF-8");
System.out.print(content);
}
} catch (IOException e) {
// 捕获IO异常(文件不存在、权限不足等)
e.printStackTrace();
}
}
}
代码说明:
byte[] buffer = new byte[1024]:缓冲区是IO高效读写的关键,避免每次只读1字节(频繁IO操作耗时);new String(buffer, 0, len, "UTF-8"):必须指定编码,否则默认使用系统编码(Windows是GBK,Linux是UTF-8,容易乱码);try-with-resources:流对象在try括号内声明,代码执行完自动关闭,无需手动写fis.close()。
案例2:写入文件内容(字节流)
需求:将字符串“Java IO 实战”写入output.txt,若文件不存在则创建,存在则覆盖。
import java.io.FileOutputStream;
import java.io.IOException;
public class FileByteWriteDemo {
public static void main(String[] args) {
String content = "Java IO 实战";
// 追加内容:在构造方法加true(默认false=覆盖)
try (FileOutputStream fos = new FileOutputStream("output.txt", true)) {
// 字符串转字节数组(指定UTF-8编码)
byte[] data = content.getBytes("UTF-8");
fos.write(data); // 写入字节数组
fos.flush(); // 强制刷新缓冲区(确保数据立即写入文件)
System.out.println("写入成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
代码说明:
FileOutputStream("output.txt", true):第二个参数true表示“追加模式”,不会覆盖原有内容;fos.flush():字节流缓冲区满了才会自动写入,flush()强制清空缓冲区,避免数据残留(字符流同理)。
场景2:字符流读写文本文件(专门处理文本,避免乱码)
字符流是字节流的“包装”,自动处理编码转换,适合读写文本文件(.txt、.md等),核心类:FileReader(读)、FileWriter(写)。
案例3:字符流读取文本文件
需求:读取test.txt(UTF-8编码)的文本内容,按行打印。
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;
public class FileCharReadDemo {
public static void main(String[] args) {
// 包装流:BufferedReader(缓冲字符流,支持按行读取)
try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
String line; // 记录每行内容
// readLine():读取一行文本,返回null表示结束
while ((line = br.readLine()) != null) {
System.out.println("行内容:" + line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
代码说明:
BufferedReader是“缓冲包装流”,基于FileReader增强,提供readLine()按行读取,效率比直接用FileReader高;FileReader默认使用系统编码,若文件是UTF-8编码且系统编码不是UTF-8(如Windows),会乱码!解决方案:用InputStreamReader指定编码:// 解决乱码:FileInputStream + InputStreamReader(手动指定编码) BufferedReader br = new BufferedReader( new InputStreamReader(new FileInputStream("test.txt"), "UTF-8") );
案例4:字符流写入文本文件
需求:将多行文本写入note.txt,按行分隔。
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.IOException;
public class FileCharWriteDemo {
public static void main(String[] args) {
// BufferedWriter:缓冲字符流,支持newLine()换行
try (BufferedWriter bw = new BufferedWriter(new FileWriter("note.txt"))) {
bw.write("第一行:Java IO 字符流");
bw.newLine(); // 跨平台换行(Windows是\r\n,Linux是\n,自动适配)
bw.write("第二行:BufferedWriter 实战");
bw.flush(); // 刷新缓冲区
System.out.println("写入完成!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
代码说明:
bw.newLine():比手动写\n更通用,自动适配操作系统的换行符;- 若需指定编码,用
OutputStreamWriter包装FileOutputStream:BufferedWriter bw = new BufferedWriter( new OutputStreamWriter(new FileOutputStream("note.txt"), "UTF-8") );
三、进阶实操:IO流的“包装思想”(核心技巧)
Java IO的设计核心是“装饰器模式”——通过“基础流+包装流”的组合,实现功能增强。比如:
- 基础流:
FileInputStream(读文件字节)、FileOutputStream(写文件字节); - 包装流:
- 缓冲流:
BufferedInputStream/BufferedOutputStream(提升读写效率); - 转换流:
InputStreamReader/OutputStreamWriter(字节流转字符流,指定编码); - 数据流:
DataInputStream/DataOutputStream(读写基本数据类型,如int、double)。
- 缓冲流:
场景3:用数据流读写基本数据类型
需求:将int、double类型的数据写入文件,再读取出来(适合存储配置、数值数据)。
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class DataStreamDemo {
public static void main(String[] args) {
// 写入基本数据类型
try (DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.dat"))) {
dos.writeInt(100); // 写int类型
dos.writeDouble(3.14159); // 写double类型
dos.writeUTF("Java IO 数据流"); // 写UTF-8字符串
System.out.println("数据写入成功!");
} catch (IOException e) {
e.printStackTrace();
}
// 读取基本数据类型(注意:读取顺序必须和写入顺序一致!)
try (DataInputStream dis = new DataInputStream(new FileInputStream("data.dat"))) {
int num = dis.readInt();
double pi = dis.readDouble();
String str = dis.readUTF();
System.out.println("读取结果:num=" + num + ", pi=" + pi + ", str=" + str);
} catch (IOException e) {
e.printStackTrace();
}
}
}
代码说明:
- 数据流的核心优势:能直接读写
int、double等基本类型,无需手动转换; - 关键注意:读取顺序必须和写入顺序完全一致(如先写int再写double,读取时也必须先读int再读double),否则会报
EOFException或数据错乱。
场景4:文件复制(IO流综合实战)
需求:复制一张图片(或视频、文档),从source.jpg到target.jpg(字节流万能复制,适合任意文件)。
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileCopyDemo {
public static void main(String[] args) {
// 源文件路径和目标文件路径
String sourcePath = "source.jpg";
String targetPath = "target.jpg";
long startTime = System.currentTimeMillis(); // 记录开始时间
// 用缓冲流包装基础流,提升复制效率
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourcePath));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(targetPath))) {
byte[] buffer = new byte[4096]; // 4KB缓冲区(常用最优大小)
int len;
while ((len = bis.read(buffer)) != -1) {
bos.write(buffer, 0, len); // 写入实际读取的字节数
}
bos.flush(); // 确保最后一批数据写入
long endTime = System.currentTimeMillis();
System.out.println("复制完成!耗时:" + (endTime - startTime) + "ms");
} catch (IOException e) {
e.printStackTrace();
}
}
}
代码说明:
- 复制文件必须用字节流(字符流会损坏非文本文件,如图片、视频);
byte[] buffer = new byte[4096]:缓冲区大小建议设为2^n(如1024、4096、8192),平衡内存占用和效率;- 缓冲流(
BufferedInputStream/BufferedOutputStream)能减少磁盘IO次数,比直接用基础流快10倍以上。
四、Java 8+ 新特性:NIO.2(Files工具类,简化IO操作)
Java 7引入的NIO.2(java.nio.file包)提供了更简洁的IO API,Files工具类封装了常用操作(读文件、写文件、复制、删除等),无需手动处理流,代码更简洁。
场景5:用Files工具类快速读写文本文件
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.io.IOException;
public class FilesDemo {
public static void main(String[] args) {
String filePath = "test.txt";
try {
// 1. 读取所有行(自动按行分割,返回List<String>)
List<String> lines = Files.readAllLines(Paths.get(filePath), java.nio.charset.StandardCharsets.UTF_8);
System.out.println("文件内容:");
for (String line : lines) {
System.out.println(line);
}
// 2. 写入文件(覆盖原有内容)
String content = "Files工具类实战:简化IO操作";
Files.write(Paths.get("newFile.txt"), content.getBytes(StandardCharsets.UTF_8));
// 3. 复制文件(一行代码搞定)
Files.copy(Paths.get("source.jpg"), Paths.get("target_nio.jpg"));
System.out.println("操作完成!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
代码说明:
Files.readAllLines():一次性读取所有行,适合小文件(大文件不推荐,会占用大量内存);Files.write():自动创建文件(父目录不存在会抛异常),支持字节数组、集合等参数;- 优势:代码简洁,无需手动管理流,自动处理资源关闭,是Java 8+推荐的简洁IO方式。
五、常见错误与避坑指南(新手必看)
-
乱码问题:
- 原因:字节流读文本时编码不匹配,或字符流未指定编码;
- 解决方案:始终用
InputStreamReader/OutputStreamWriter指定UTF-8编码,或用Files工具类显式指定编码。
-
资源泄露:
- 原因:忘记关闭流,导致文件被占用、内存泄露;
- 解决方案:强制使用
try-with-resources声明流(自动关闭),避免手动close()(容易遗漏)。
-
文件路径错误:
- 原因:相对路径写错(如
test.txt实际在src/main/resources下,而非项目根目录); - 解决方案:用绝对路径测试(如
C:/test.txt),或通过ClassLoader获取资源路径:// 获取resources目录下的文件 String path = FileCopyDemo.class.getClassLoader().getResource("test.txt").getPath();
- 原因:相对路径写错(如
-
缓冲区未刷新:
- 原因:写入流后未调用
flush(),缓冲区数据未写入文件; - 解决方案:写入完成后调用
flush(),或依赖try-with-resources自动刷新。
- 原因:写入流后未调用
六、学习路线建议(从易到难)
- 第一步:掌握字节流基础(
FileInputStream/FileOutputStream),实现文件读写、复制; - 第二步:学习字符流(
FileReader/FileWriter)+ 缓冲流(BufferedReader/BufferedWriter),处理文本文件; - 第三步:理解包装思想,学习转换流、数据流,掌握“基础流+包装流”的组合用法;
- 第四步:学习NIO.2(
Files工具类),简化日常IO操作; - 第五步:进阶学习NIO(通道、缓冲区),应对高并发IO场景(如网络编程)。
总结
Java IO学习的核心是“先理解流的模型,再分场景实操”。新手建议从文件读写、复制等简单场景入手,先能用起来,再深入理解“装饰器模式”“缓冲区原理”等底层逻辑。记住:IO编程的关键是“选对流、关对资源、避乱码”,多动手写案例(如复制文件、读写配置),很快就能熟练掌握。
更多推荐

所有评论(0)