Java IO 流:从字节到字符再到Java 装饰者模式(Decorator Pattern),解析与应用掌握数据流动的艺术
在 Java 编程中,IO(输入输出)流是处理数据输入输出的核心工具。无论是读取文件、网络通信,还是处理用户输入,IO 流都扮演着重要角色。本文将深入探讨 Java IO 流的核心概念、分类、经典代码实例及其应用场景,帮助你全面掌握数据流动的艺术。
1. Java IO 流的核心概念
1.1 什么是 IO 流?
IO 流是 Java 中用于处理输入输出数据的抽象概念。它可以将数据从一个地方(如文件、网络)传输到另一个地方(如内存、控制台)。
1.2 IO 流的分类
-
按数据单位:
-
字节流:以字节为单位读写数据,适用于二进制文件(如图片、视频)。
-
字符流:以字符为单位读写数据,适用于文本文件。
-
-
按流向:
-
输入流:从外部读取数据到程序中。
-
输出流:将程序中的数据写入外部。
-
2. Java IO 流的经典类
2.1 字节流
字节流主要用于处理二进制数据。Java 提供了 InputStream
和 OutputStream
作为字节流的基类。
-
InputStream:字节输入流的基类。
-
常用实现类:
FileInputStream
、BufferedInputStream
。
-
-
OutputStream:字节输出流的基类。
-
常用实现类:
FileOutputStream
、BufferedOutputStream
。
-
2.2 字符流
-
Reader:字符输入流的基类。
-
常用实现类:
FileReader
、BufferedReader
。
-
-
Writer:字符输出流的基类。
-
常用实现类:
FileWriter
、BufferedWriter
。
-
3. 经典代码实例
3.1 字节流:文件复制
以下是一个使用字节流复制文件的示例:
//代码解读:
//使用 FileInputStream 读取源文件。
//
//FileOutputStream 写入目标文件。
//
//通过缓冲区 byte[] buffer 提高读写效率。
//使用 try-with-resources 语法自动关闭流。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamExample {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("source.txt");
FileOutputStream fos = new FileOutputStream("target.txt")) {
byte[] buffer = new byte[1024];
int length;
while ((length = fis.read(buffer)) != -1) {
fos.write(buffer, 0, length);
}
System.out.println("文件复制完成!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.2 字符流:文本文件读取
以下是一个使用字符流读取文本文件的示例:
//代码解读:
//使用 FileReader 读取文本文件。
//使用 BufferedReader 包装 FileReader,提高读取效率。
通过 readLine() 方法逐行读取文件内容。
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class CharStreamExample {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("source.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.3 缓冲流:高效文件读写
以下是一个使用缓冲流读写文件的示例:
//使用 BufferedReader 和 BufferedWriter 包装字符流,提高读写效率。
//通过 readLine() 和 write() 方法逐行读写文件。
import java.io.*;
public class BufferedStreamExample {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("source.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("target.txt"))) {
String line;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine(); // 写入换行符
}
System.out.println("文件读写完成!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.4 对象流:序列化与反序列化
Java 提供 ObjectOutputStream
和 ObjectInputStream
来进行对象的序列化和反序列化。
import java.io.*;
class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
public class ObjectStreamExample {
public static void main(String[] args) {
String filePath = "person.ser";
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath))) {
Person p = new Person("Alice", 25);
oos.writeObject(p);
} catch (IOException e) {
e.printStackTrace();
}
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath))) {
Person p = (Person) ois.readObject();
System.out.println("反序列化对象: " + p);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
3.5 转换流:示例
转换流 适用于字节与字符的转换,支持编码格式转换。
import java.io.*;
public class ConvertStreamExample {
public static void main(String[] args) {
try (OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("example.txt"), "UTF-8")) {
osw.write("你好,世界!");
} catch (IOException e) {
e.printStackTrace();
}
try (InputStreamReader isr = new InputStreamReader(new FileInputStream("example.txt"), "UTF-8")) {
int data;
while ((data = isr.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.6 PrintStream 和 PrintWriter
import java.io.PrintStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class PrintStreamExample {
public static void main(String[] args) {
try (PrintStream ps = new PrintStream(new FileOutputStream("printStream.txt"))) {
ps.println("Hello, PrintStream!");
ps.printf("Formatted number: %.2f", 123.456);
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.PrintWriter;
import java.io.FileWriter;
import java.io.IOException;
public class PrintWriterExample {
public static void main(String[] args) {
try (PrintWriter pw = new PrintWriter(new FileWriter("printWriter.txt"))) {
pw.println("Hello, PrintWriter!");
pw.printf("Formatted text: %s", "Java IO");
} catch (IOException e) {
e.printStackTrace();
}
}
}
4. 装饰者模式(Decorator Pattern)
在 Java 语言中,装饰者模式(Decorator Pattern) 是一种结构型设计模式,它允许动态地为对象添加新功能,而不改变其原始结构。在 Java 的 IO(输入/输出)系统中,装饰者模式被广泛应用,例如 BufferedReader
便是 Reader
的装饰者。
4.1. 装饰者模式概述
装饰者模式的特点
-
增强功能:在不修改原有类的情况下,动态添加新功能。
-
符合开闭原则(OCP):对扩展开放,对修改封闭。
-
支持递归组合:装饰者可以装饰另一个装饰者,实现更复杂的功能。
典型应用场景
-
Java IO(
BufferedReader
装饰FileReader
提高效率)。 -
图形界面(
BorderDecorator
装饰Window
以增加边框)。 -
数据加密(
DataStream
装饰FileStream
以增加加密功能)。
4.2 代码示例:基于装饰者模式的 Reader 设计
在 Decorator_pattern
目录下,我们设计了一组 Reader_
类,它们模仿 Java IO 中的 Reader
,并通过装饰者模式扩展其功能。
Reader_(抽象基类)
//作用:
//Reader_ 是抽象基类,定义了 read() 和 readLine() 方法。
//允许子类继承,实现具体的读取方式。
import java.io.Reader;
import java.io.IOException;
abstract class Reader_ {
protected Reader reader;
public Reader_(Reader reader) {
this.reader = reader;
}
public abstract int read() throws IOException;
public abstract String readLine() throws IOException;
public void close() throws IOException {
reader.close();
}
}
File_reader_(从文件读取数据)
//作用:
//
//直接从文件读取字符。
//不支持 readLine(),需要 BufferedReader 进行封装。
import java.io.FileReader;
import java.io.IOException;
class File_reader_ extends Reader_ {
public File_reader_(String filePath) throws IOException {
super(new FileReader(filePath));
}
@Override
public int read() throws IOException {
return reader.read();
}
@Override
public String readLine() throws IOException {
throw new UnsupportedOperationException("FileReader 不支持 readLine");
}
}
Buffered_reader_(增强 File_reader_,增加缓冲)
//作用:
//BufferedReader 的封装,提供 readLine() 方法。
//装饰 File_reader_,增强其功能。
class Buffered_reader_ extends Reader_ {
private BufferedReader bufferedReader;
public Buffered_reader_(Reader_ reader) {
super(reader.reader);
this.bufferedReader = new BufferedReader(reader);
}
@Override
public int read() throws IOException {
return bufferedReader.read();
}
@Override
public String readLine() throws IOException {
return bufferedReader.readLine();
}
}
String_reader_(从字符串读取数据)
//作用:
//直接从 String 读取数据,而不是文件。
import java.io.StringReader;
import java.io.IOException;
class String_reader_ extends Reader_ {
public String_reader_(String data) {
super(new StringReader(data));
}
@Override
public int read() throws IOException {
return reader.read();
}
@Override
public String readLine() throws IOException {
throw new UnsupportedOperationException("StringReader 不支持 readLine");
}
}
Test(测试代码)
import java.io.IOException;
public class Test {
public static void main(String[] args) {
try {
System.out.println("读取文件示例:");
Reader_ fileReader = new File_reader_("example.txt");
Reader_ bufferedReader = new Buffered_reader_(fileReader);
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
bufferedReader.close();
System.out.println("\n读取字符串示例:");
Reader_ stringReader = new String_reader_("Hello, World!");
int ch;
while ((ch = stringReader.read()) != -1) {
System.out.print((char) ch);
}
stringReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4.3 小结
通过装饰者模式,我们可以 灵活组合不同的 Reader_
类,增强功能。
5. IO 流的应用场景
5.1 文件操作
-
读取、写入、复制、删除文件。
-
示例:日志文件处理、配置文件读取。
5.2 网络通信
-
通过
Socket
实现客户端和服务器之间的数据传输。 -
示例:文件传输、实时聊天。
5.3 数据处理
-
解析 CSV、JSON 等格式的数据。
-
示例:数据导入导出、数据分析。
6. IO 流的最佳实践
6.1 使用缓冲流
-
缓冲流(如
BufferedReader
、BufferedInputStream
)可以显著提高 IO 性能。
6.2 使用 try-with-resources
-
确保流在使用后自动关闭,避免资源泄漏。
6.3 处理大文件
-
对于大文件,使用分块读写(如
byte[] buffer
)避免内存溢出。
7. 总结
Java IO 流是处理数据输入输出的核心工具,涵盖了字节流、字符流、缓冲流等多种类型。通过经典代码实例和最佳实践,本文帮助你全面掌握 IO 流的使用方法。无论是文件操作、网络通信,还是数据处理,IO 流都能为你提供强大的支持。