Appearance
IO流
IO流用于处理数据的输入和输出操作。Java 提供了丰富的 IO 流类来处理文件、网络等数据传输。
IO流概述
流的分类
text
┌─────────────────────────────────────────────────────────────────┐
│ IO流分类 │
├─────────────────────────────────────────────────────────────────┤
│ 按数据流向: │
│ - 输入流(InputStream/Reader):读取数据 │
│ - 输出流(OutputStream/Writer):写出数据 │
│ │
│ 按数据类型: │
│ - 字节流:处理所有类型数据(图片、视频、文本等) │
│ - 字符流:处理文本数据(自动处理编码问题) │
│ │
│ 按功能: │
│ - 节点流:直接操作数据源 │
│ - 处理流:包装节点流,增强功能 │
└─────────────────────────────────────────────────────────────────┘流的体系
text
┌─────────────────────────────────────────────────────────────────┐
│ IO流体系 │
├─────────────────────────────────────────────────────────────────┤
│ 字节流: │
│ InputStream OutputStream │
│ ├── FileInputStream ├── FileOutputStream │
│ ├── BufferedInputStream ├── BufferedOutputStream │
│ ├── ObjectInputStream ├── ObjectOutputStream │
│ └── ByteArrayInputStream └── ByteArrayOutputStream │
│ │
│ 字符流: │
│ Reader Writer │
│ ├── FileReader ├── FileWriter │
│ ├── BufferedReader ├── BufferedWriter │
│ ├── InputStreamReader ├── OutputStreamWriter │
│ └── StringReader └── StringWriter │
└─────────────────────────────────────────────────────────────────┘文件操作
File 类
File 类表示文件或目录的路径。
java
import java.io.*;
public class FileDemo {
public static void main(String[] args) throws IOException {
// 创建 File 对象
File file = new File("test.txt");
File dir = new File("mydir");
// 文件信息
System.out.println("文件名:" + file.getName());
System.out.println("绝对路径:" + file.getAbsolutePath());
System.out.println("父目录:" + file.getParent());
System.out.println("是否存在:" + file.exists());
System.out.println("是否文件:" + file.isFile());
System.out.println("是否目录:" + file.isDirectory());
System.out.println("文件大小:" + file.length() + " 字节");
System.out.println("最后修改:" + file.lastModified());
// 创建文件
if (!file.exists()) {
boolean created = file.createNewFile();
System.out.println("文件创建:" + (created ? "成功" : "失败"));
}
// 创建目录
if (!dir.exists()) {
boolean created = dir.mkdirs(); // 创建多级目录
System.out.println("目录创建:" + (created ? "成功" : "失败"));
}
// 删除文件
// boolean deleted = file.delete();
// System.out.println("文件删除:" + (deleted ? "成功" : "失败"));
// 重命名
File newFile = new File("renamed.txt");
// file.renameTo(newFile);
// 遍历目录
File root = new File(".");
String[] list = root.list();
if (list != null) {
System.out.println("\n当前目录内容:");
for (String name : list) {
System.out.println(name);
}
}
// 过滤文件
File[] javaFiles = root.listFiles((d, name) -> name.endsWith(".java"));
System.out.println("\nJava 文件:");
if (javaFiles != null) {
for (File f : javaFiles) {
System.out.println(f.getName());
}
}
}
}字节流
FileInputStream 和 FileOutputStream
java
import java.io.*;
public class FileStreamDemo {
public static void main(String[] args) {
// 写入文件
try (FileOutputStream fos = new FileOutputStream("output.txt")) {
String content = "Hello, Java IO!\n你好,Java IO!";
fos.write(content.getBytes());
System.out.println("写入成功");
} catch (IOException e) {
e.printStackTrace();
}
// 读取文件(逐字节)
try (FileInputStream fis = new FileInputStream("output.txt")) {
int data;
System.out.println("\n逐字节读取:");
while ((data = fis.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
// 读取文件(字节数组)
try (FileInputStream fis = new FileInputStream("output.txt")) {
byte[] buffer = new byte[1024];
int len;
System.out.println("\n\n字节数组读取:");
while ((len = fis.read(buffer)) != -1) {
System.out.print(new String(buffer, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
// 文件复制
copyFile("output.txt", "copy.txt");
}
/**
* 文件复制方法
*/
public static void copyFile(String src, String dest) {
try (FileInputStream fis = new FileInputStream(src);
FileOutputStream fos = new FileOutputStream(dest)) {
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
System.out.println("\n\n复制成功");
} catch (IOException e) {
e.printStackTrace();
}
}
}BufferedInputStream 和 BufferedOutputStream
java
import java.io.*;
public class BufferedStreamDemo {
public static void main(String[] args) {
// 使用缓冲流提高效率
long start, end;
// 不使用缓冲流
start = System.currentTimeMillis();
copyWithoutBuffer("largefile.zip", "copy1.zip");
end = System.currentTimeMillis();
System.out.println("不使用缓冲流耗时:" + (end - start) + " ms");
// 使用缓冲流
start = System.currentTimeMillis();
copyWithBuffer("largefile.zip", "copy2.zip");
end = System.currentTimeMillis();
System.out.println("使用缓冲流耗时:" + (end - start) + " ms");
}
// 不使用缓冲流
public static void copyWithoutBuffer(String src, String dest) {
try (FileInputStream fis = new FileInputStream(src);
FileOutputStream fos = new FileOutputStream(dest)) {
int data;
while ((data = fis.read()) != -1) {
fos.write(data);
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 使用缓冲流
public static void copyWithBuffer(String src, String dest) {
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(src));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest))) {
byte[] buffer = new byte[8192];
int len;
while ((len = bis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}字符流
FileReader 和 FileWriter
java
import java.io.*;
public class FileReaderWriterDemo {
public static void main(String[] args) {
// 写入文件
try (FileWriter fw = new FileWriter("chars.txt")) {
fw.write("Hello, Java!\n");
fw.write("你好,Java!\n");
fw.write("字符流处理文本更方便");
System.out.println("写入成功");
} catch (IOException e) {
e.printStackTrace();
}
// 读取文件(逐字符)
try (FileReader fr = new FileReader("chars.txt")) {
int ch;
System.out.println("\n逐字符读取:");
while ((ch = fr.read()) != -1) {
System.out.print((char) ch);
}
} catch (IOException e) {
e.printStackTrace();
}
// 读取文件(字符数组)
try (FileReader fr = new FileReader("chars.txt")) {
char[] buffer = new char[1024];
int len;
System.out.println("\n\n字符数组读取:");
while ((len = fr.read(buffer)) != -1) {
System.out.print(new String(buffer, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}BufferedReader 和 BufferedWriter
java
import java.io.*;
public class BufferedReadWriteDemo {
public static void main(String[] args) {
// 写入文件
try (BufferedWriter bw = new BufferedWriter(new FileWriter("lines.txt"))) {
bw.write("第一行");
bw.newLine(); // 换行
bw.write("第二行");
bw.newLine();
bw.write("第三行");
System.out.println("写入成功");
} catch (IOException e) {
e.printStackTrace();
}
// 读取文件(按行)
try (BufferedReader br = new BufferedReader(new FileReader("lines.txt"))) {
String line;
System.out.println("\n按行读取:");
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}InputStreamReader 和 OutputStreamWriter
java
import java.io.*;
public class StreamReaderWriterDemo {
public static void main(String[] args) {
// 指定编码写入
try (OutputStreamWriter osw = new OutputStreamWriter(
new FileOutputStream("utf8.txt"), "UTF-8")) {
osw.write("UTF-8 编码的文本\n");
osw.write("你好,世界!");
System.out.println("UTF-8 写入成功");
} catch (IOException e) {
e.printStackTrace();
}
// 指定编码读取
try (InputStreamReader isr = new InputStreamReader(
new FileInputStream("utf8.txt"), "UTF-8")) {
char[] buffer = new char[1024];
int len;
System.out.println("\nUTF-8 读取:");
while ((len = isr.read(buffer)) != -1) {
System.out.print(new String(buffer, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
// GBK 编码
try (OutputStreamWriter osw = new OutputStreamWriter(
new FileOutputStream("gbk.txt"), "GBK")) {
osw.write("GBK 编码的文本");
System.out.println("\n\nGBK 写入成功");
} catch (IOException e) {
e.printStackTrace();
}
}
}对象流
序列化和反序列化
java
import java.io.*;
// 实现 Serializable 接口的类可以被序列化
class Person implements Serializable {
private static final long serialVersionUID = 1L; // 序列化版本号
private String name;
private int age;
private transient String password; // transient 表示不参与序列化
public Person(String name, int age, String password) {
this.name = name;
this.age = age;
this.password = password;
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age +
", password='" + password + "'}";
}
}
public class ObjectStreamDemo {
public static void main(String[] args) {
// 序列化:对象 → 文件
Person person = new Person("张三", 25, "123456");
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("person.obj"))) {
oos.writeObject(person);
System.out.println("序列化成功:" + person);
} catch (IOException e) {
e.printStackTrace();
}
// 反序列化:文件 → 对象
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("person.obj"))) {
Person p = (Person) ois.readObject();
System.out.println("反序列化成功:" + p);
// password 为 null(transient 字段不序列化)
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
// 序列化多个对象
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("persons.obj"))) {
oos.writeObject(new Person("张三", 25, "111"));
oos.writeObject(new Person("李四", 30, "222"));
oos.writeObject(new Person("王五", 28, "333"));
System.out.println("\n序列化多个对象成功");
} catch (IOException e) {
e.printStackTrace();
}
// 反序列化多个对象
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("persons.obj"))) {
System.out.println("反序列化多个对象:");
while (true) {
try {
Person p = (Person) ois.readObject();
System.out.println(p);
} catch (EOFException e) {
break; // 文件结束
}
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}打印流
java
import java.io.*;
public class PrintStreamDemo {
public static void main(String[] args) throws FileNotFoundException {
// PrintStream:字节打印流
try (PrintStream ps = new PrintStream("print.txt")) {
ps.println("Hello, PrintStream!");
ps.println(123);
ps.println(3.14);
ps.printf("格式化输出:%s, %d, %.2f%n", "Java", 100, 3.14159);
System.out.println("PrintStream 写入成功");
}
// PrintWriter:字符打印流
try (PrintWriter pw = new PrintWriter(new FileWriter("printwriter.txt"))) {
pw.println("Hello, PrintWriter!");
pw.println("支持自动刷新");
pw.format("格式化:%d + %d = %d%n", 1, 2, 3);
System.out.println("PrintWriter 写入成功");
}
// 重定向标准输出
PrintStream originalOut = System.out;
System.setOut(new PrintStream("console.txt"));
System.out.println("这行会写入文件");
System.setOut(originalOut);
System.out.println("这行输出到控制台");
}
}标准输入输出
java
import java.io.*;
import java.util.Scanner;
public class StandardIODemo {
public static void main(String[] args) {
// 标准输入流
System.out.println("请输入内容(输入 exit 退出):");
// 方式一:使用 BufferedReader
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
String line;
while (!(line = br.readLine()).equals("exit")) {
System.out.println("你输入了:" + line);
}
} catch (IOException e) {
e.printStackTrace();
}
// 方式二:使用 Scanner(推荐)
Scanner scanner = new Scanner(System.in);
System.out.println("\n使用 Scanner:");
System.out.print("请输入姓名:");
String name = scanner.nextLine();
System.out.print("请输入年龄:");
int age = scanner.nextInt();
System.out.println("姓名:" + name + ",年龄:" + age);
scanner.close();
// 标准错误流
System.err.println("\n这是错误输出");
}
}NIO 文件操作
Java 7+ 提供了 NIO.2 文件 API,更简洁高效。
java
import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.io.IOException;
import java.util.List;
public class NIOFileDemo {
public static void main(String[] args) throws IOException {
Path path = Paths.get("nio_test.txt");
// 写入文件
Files.write(path, "Hello, NIO!\n你好,NIO!".getBytes(StandardCharsets.UTF_8));
System.out.println("写入成功");
// 读取所有内容
String content = Files.readString(path);
System.out.println("\n读取全部内容:\n" + content);
// 读取所有行
List<String> lines = Files.readAllLines(path);
System.out.println("\n按行读取:");
lines.forEach(System.out::println);
// 追加内容
Files.write(path, "\n追加的内容".getBytes(StandardCharsets.UTF_8),
StandardOpenOption.APPEND);
// 文件信息
System.out.println("\n文件信息:");
System.out.println("文件名:" + path.getFileName());
System.out.println("文件大小:" + Files.size(path) + " 字节");
System.out.println("是否可读:" + Files.isReadable(path));
System.out.println("是否可写:" + Files.isWritable(path));
// 创建目录
Path dir = Paths.get("nio_dir");
Files.createDirectories(dir);
// 复制文件
Path copy = Paths.get("nio_copy.txt");
Files.copy(path, copy, StandardCopyOption.REPLACE_EXISTING);
System.out.println("\n复制成功");
// 移动/重命名文件
Path moved = Paths.get("nio_moved.txt");
Files.move(copy, moved, StandardCopyOption.REPLACE_EXISTING);
System.out.println("移动成功");
// 删除文件
Files.deleteIfExists(moved);
System.out.println("删除成功");
// 遍历目录
System.out.println("\n遍历当前目录:");
try (DirectoryStream<Path> stream = Files.newDirectoryStream(Paths.get("."))) {
for (Path p : stream) {
System.out.println(p.getFileName() +
(Files.isDirectory(p) ? "/" : ""));
}
}
// 递归遍历(深度优先)
System.out.println("\n递归遍历:");
Files.walk(Paths.get("."))
.filter(p -> p.toString().endsWith(".java"))
.limit(5)
.forEach(System.out::println);
}
}小结
本章我们学习了:
- File 类:文件和目录的操作
- 字节流:FileInputStream、FileOutputStream、BufferedInputStream、BufferedOutputStream
- 字符流:FileReader、FileWriter、BufferedReader、BufferedWriter
- 转换流:InputStreamReader、OutputStreamWriter
- 对象流:ObjectInputStream、ObjectOutputStream
- 打印流:PrintStream、PrintWriter
- NIO 文件操作:Files、Path 类
下一章,我们将学习 多线程,了解 Java 的并发编程。
