Java File类与IO流详解:从基础到实战
·
1. 引言
在Java编程中,文件操作和输入输出(IO)是日常开发中不可或缺的部分。无论是读取配置文件、处理日志文件,还是实现数据持久化,都需要用到Java的File类和IO流。本文将深入讲解Java中File类的基本用法、IO流的分类体系,并通过丰富的代码示例帮助您掌握这些核心概念。
2. File类:文件与目录的操作
2.1 File类概述
java.io.File类是Java中用于表示文件和目录路径名的抽象表示。它提供了创建、删除、重命名文件和目录,以及查询文件属性等功能。
import java.io.File;
public class FileBasicExample {
public static void main(String[] args) {
// 创建File对象(不实际创建文件)
File file = new File("test.txt");
System.out.println("文件路径: " + file.getPath());
System.out.println("绝对路径: " + file.getAbsolutePath());
System.out.println("文件名: " + file.getName());
// 检查文件是否存在
if (file.exists()) {
System.out.println("文件存在");
System.out.println("文件大小: " + file.length() + " bytes");
System.out.println("是否可读: " + file.canRead());
System.out.println("是否可写: " + file.canWrite());
} else {
System.out.println("文件不存在");
}
}
}
2.2 文件与目录操作
import java.io.File;
import java.io.IOException;
public class FileOperations {
public static void main(String[] args) {
// 创建文件
File newFile = new File("newfile.txt");
try {
if (newFile.createNewFile()) {
System.out.println("文件创建成功: " + newFile.getName());
} else {
System.out.println("文件已存在");
}
} catch (IOException e) {
e.printStackTrace();
}
// 创建目录
File dir = new File("mydir");
if (dir.mkdir()) {
System.out.println("目录创建成功");
}
// 列出目录内容
File currentDir = new File(".");
System.out.println("\n当前目录内容:");
String[] files = currentDir.list();
if (files != null) {
for (String fileName : files) {
System.out.println(fileName);
}
}
// 删除文件
if (newFile.delete()) {
System.out.println("\n文件删除成功");
}
}
}
3. IO流体系结构
3.1 流的分类
Java IO流按照不同的维度可以分为:
-
按数据流向:
- 输入流(InputStream/Reader):从数据源读取数据
- 输出流(OutputStream/Writer):向目标写入数据
-
按处理单位:
- 字节流:以字节为单位(8位),适合处理所有类型文件
- 字符流:以字符为单位(16位),适合处理文本文件
-
按功能:
- 节点流:直接从数据源读写数据
- 处理流:对节点流进行包装,提供增强功能
3.2 字节流(Byte Streams)
字节流用于处理二进制数据,如图片、音频、视频等。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamExample {
// 使用FileInputStream读取文件
public static void readFile(String filePath) {
try (FileInputStream fis = new FileInputStream(filePath)) {
int byteData;
System.out.println("文件内容(字节形式):");
while ((byteData = fis.read()) != -1) {
System.out.print((char) byteData);
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 使用FileOutputStream写入文件
public static void writeFile(String filePath, String content) {
try (FileOutputStream fos = new FileOutputStream(filePath)) {
byte[] bytes = content.getBytes();
fos.write(bytes);
System.out.println("文件写入成功");
} catch (IOException e) {
e.printStackTrace();
}
}
// 文件复制(字节流方式)
public static void copyFile(String source, String destination) {
try (FileInputStream fis = new FileInputStream(source);
FileOutputStream fos = new FileOutputStream(destination)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
fos.write(buffer, 0, bytesRead);
}
System.out.println("文件复制完成");
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// 写入文件
writeFile("test.txt", "Hello, Java IO Stream!");
// 读取文件
readFile("test.txt");
// 复制文件
copyFile("test.txt", "test_copy.txt");
}
}
3.3 字符流(Character Streams)
字符流专门用于处理文本文件,支持字符编码。
import java.io.FileReader;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
public class CharacterStreamExample {
// 使用FileReader和FileWriter
public static void basicReadWrite() {
// 写入文件
try (FileWriter writer = new FileWriter("textfile.txt")) {
writer.write("Java字符流示例\n");
writer.write("第二行内容\n");
writer.write("第三行内容");
System.out.println("文件写入完成");
} catch (IOException e) {
e.printStackTrace();
}
// 读取文件
try (FileReader reader = new FileReader("textfile.txt")) {
int charData;
System.out.println("\n文件内容:");
while ((charData = reader.read()) != -1) {
System.out.print((char) charData);
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 使用缓冲流提高效率
public static void bufferedStreamExample() {
// 使用BufferedWriter写入
try (BufferedWriter bw = new BufferedWriter(new FileWriter("buffered.txt"))) {
bw.write("使用缓冲流写入数据");
bw.newLine();
bw.write("这是第二行");
bw.newLine();
bw.write("性能更好,效率更高");
System.out.println("缓冲写入完成");
} catch (IOException e) {
e.printStackTrace();
}
// 使用BufferedReader读取
try (BufferedReader br = new BufferedReader(new FileReader("buffered.txt"))) {
String line;
System.out.println("\n使用缓冲流读取:");
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
basicReadWrite();
bufferedStreamExample();
}
}
4. 高级IO操作
4.1 对象序列化
Java提供了对象序列化机制,可以将对象转换为字节序列进行存储或传输。
import java.io.*;
import java.util.Date;
// 可序列化的类
class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
private Date birthDate;
public Person(String name, int age, Date birthDate) {
this.name = name;
this.age = age;
this.birthDate = birthDate;
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age +
", birthDate=" + birthDate + "}";
}
}
public class ObjectStreamExample {
// 序列化对象到文件
public static void serializeObject(Person person, String filePath) {
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream(filePath))) {
oos.writeObject(person);
System.out.println("对象序列化完成: " + person);
} catch (IOException e) {
e.printStackTrace();
}
}
// 从文件反序列化对象
public static Person deserializeObject(String filePath) {
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream(filePath))) {
Person person = (Person) ois.readObject();
System.out.println("对象反序列化完成: " + person);
return person;
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
Person person = new Person("张三", 25, new Date());
// 序列化
serializeObject(person, "person.ser");
// 反序列化
Person restoredPerson = deserializeObject("person.ser");
}
}
4.2 随机访问文件
RandomAccessFile类允许在文件的任意位置进行读写操作。
import java.io.RandomAccessFile;
import java.io.IOException;
public class RandomAccessFileExample {
public static void main(String[] args) {
String filePath = "random.dat";
try (RandomAccessFile raf = new RandomAccessFile(filePath, "rw")) {
// 写入数据
raf.writeUTF("Java"); // 写入字符串
raf.writeInt(100); // 写入整数
raf.writeDouble(3.14); // 写入双精度浮点数
// 移动到文件开头重新读取
raf.seek(0);
// 读取数据
String str = raf.readUTF();
int num = raf.readInt();
double d = raf.readDouble();
System.out.println("读取的数据:");
System.out.println("字符串: " + str);
System.out.println("整数: " + num);
System.out.println("浮点数: " + d);
// 在文件末尾追加数据
raf.seek(raf.length());
raf.writeUTF("追加的内容");
} catch (IOException e) {
e.printStackTrace();
}
}
}
5. NIO(New IO)简介
Java NIO提供了更高效的IO操作方式,主要包含三个核心组件:Channel、Buffer和Selector。
import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
public class NIOExample {
// 使用Files类简化文件操作
public static void filesExample() throws IOException {
// 写入文件
String content = "Java NIO Files类示例\n第二行内容";
Path path = Paths.get("nio_file.txt");
Files.write(path, content.getBytes(StandardCharsets.UTF_8));
System.out.println("文件写入完成");
// 读取文件
List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
System.out.println("\n文件内容:");
for (String line : lines) {
System.out.println(line);
}
// 复制文件
Path copyPath = Paths.get("nio_file_copy.txt");
Files.copy(path, copyPath, StandardCopyOption.REPLACE_EXISTING);
System.out.println("文件复制完成");
}
// 使用Path接口
public static void pathExample() {
Path path = Paths.get("src", "main", "java", "Test.java");
System.out.println("Path信息:");
System.out.println("文件名: " + path.getFileName());
System.out.println("父目录: " + path.getParent());
System.out.println("根目录: " + path.getRoot());
System.out.println("绝对路径: " + path.toAbsolutePath());
System.out.println("是否是绝对路径: " + path.isAbsolute());
// 路径操作
Path resolved = path.resolve("config.properties");
System.out.println("解析后的路径: " + resolved);
}
public static void main(String[] args) {
try {
filesExample();
pathExample();
} catch (IOException e) {
e.printStackTrace();
}
}
}
6. 最佳实践与常见问题
6.1 资源管理
正确做法(使用try-with-resources):
try (FileInputStream fis = new FileInputStream("file.txt");
FileOutputStream fos = new FileOutputStream("output.txt")) {
// 使用流
int data;
while ((data = fis.read()) != -1) {
fos.write(data);
}
} catch (IOException e) {
e.printStackTrace();
}
// 自动关闭资源,无需手动调用close()
6.2 性能优化建议
- 使用缓冲流:对于频繁的IO操作,使用BufferedInputStream/BufferedOutputStream
- 选择合适的缓冲区大小:通常8KB-64KB效果较好
- 批量读写:避免单字节读写,使用byte数组批量操作
- 及时关闭资源:防止资源泄漏
6.3 常见异常处理
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class ExceptionHandlingExample {
public static void safeFileRead(String filePath) {
File file = new File(filePath);
if (!file.exists()) {
System.out.println("文件不存在: " + filePath);
return;
}
if (!file.canRead()) {
System.out.println("文件不可读: " + filePath);
return;
}
try (Scanner scanner = new Scanner(file)) {
while (scanner.hasNextLine()) {
System.out.println(scanner.nextLine());
}
} catch (FileNotFoundException e) {
// 虽然已经检查过,但多线程环境下仍需处理
System.out.println("文件读取异常: " + e.getMessage());
}
}
public static void main(String[] args) {
safeFileRead("nonexistent.txt");
safeFileRead("test.txt");
}
}
7. 实战案例:文件加密工具
import java.io.*;
import java.util.Scanner;
public class FileEncryptor {
// 简单的XOR加密
private static byte[] xorEncrypt(byte[] data, byte key) {
byte[] encrypted = new byte[data.length];
for (int i = 0; i < data.length; i++) {
encrypted[i] = (byte) (data[i] ^ key);
}
return encrypted;
}
// 加密文件
public static void encryptFile(String sourcePath, String destPath, byte key) {
try (FileInputStream fis = new FileInputStream(sourcePath);
FileOutputStream fos = new FileOutputStream(destPath)) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
byte[] encrypted = xorEncrypt(buffer, key);
fos.write(encrypted, 0, bytesRead);
}
System.out.println("文件加密完成: " + destPath);
} catch (IOException e) {
System.err.println("加密失败: " + e.getMessage());
}
}
// 解密文件(XOR加密的解密就是再次加密)
public static void decryptFile(String sourcePath, String destPath, byte key) {
encryptFile(sourcePath, destPath, key); // XOR特性:加密=解密
System.out.println("文件解密完成: " + destPath);
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("文件加密工具");
System.out.print("请输入源文件路径: ");
String source = scanner.nextLine();
System.out.print("请输入目标文件路径: ");
String dest = scanner.nextLine();
System.out.print("请输入加密密钥(0-255): ");
byte key = (byte) scanner.nextInt();
System.out.print("请选择操作(1-加密, 2-解密): ");
int choice = scanner.nextInt();
if (choice == 1) {
encryptFile(source, dest, key);
} else if (choice == 2) {
decryptFile(source, dest, key);
} else {
System.out.println("无效选择");
}
scanner.close();
}
}
8. 总结
Java的File类和IO流提供了强大的文件操作能力:
- File类:用于文件和目录的基本操作,如创建、删除、查询属性等
- 字节流:适合处理所有类型文件,特别是二进制文件
- 字符流:专门为文本文件设计,支持字符编码
- 缓冲流:提高IO性能,减少系统调用次数
- 对象流:实现对象的序列化和反序列化
- NIO:提供更高效的IO操作方式
在实际开发中,应根据具体需求选择合适的IO类,并注意资源管理和异常处理。对于大量数据的IO操作,建议使用缓冲流和合适的缓冲区大小来优化性能。
掌握这些基础知识后,您可以更高效地处理Java中的文件操作和IO任务,为开发更复杂的应用程序打下坚实基础。
更多推荐


所有评论(0)