Java IO流实现文件操作知识点

一、IO流概述

1.1 什么是IO流

public class IOOverview {

public static void main(String[] args) {

// IO流:Input/Output Stream

// 用于处理设备之间的数据传输

System.out.println("=== Java IO流体系结构 ===");

System.out.println("按数据流向分:");

System.out.println(" 1. 输入流(Input Stream):读取数据");

System.out.println(" 2. 输出流(Output Stream):写入数据");

System.out.println("\n按数据类型分:");

System.out.println(" 1. 字节流(Byte Stream):处理所有类型数据");

System.out.println(" InputStream / OutputStream");

System.out.println(" 2. 字符流(Character Stream):处理文本数据");

System.out.println(" Reader / Writer");

System.out.println("\n按功能分:");

System.out.println(" 1. 节点流:直接从数据源/目的地读写");

System.out.println(" 2. 处理流(包装流):对节点流进行包装,提供增强功能");

}

}

二、File类 - 文件和目录操作

2.1 File类基本操作

import java.io.File;

import java.io.IOException;

import java.text.SimpleDateFormat;

import java.util.Date;

public class FileOperations {

public static void main(String[] args) {

System.out.println("=== File类操作 ===");

// 1. 创建File对象(不代表实际创建文件)

File file1 = new File("test.txt");

File file2 = new File("C:/test", "data.txt"); // 父路径 + 子路径

File file3 = new File(new File("C:/test"), "info.txt");

// 2. 文件和目录的创建

try {

// 创建文件

if (file1.createNewFile()) {

System.out.println("文件创建成功: " + file1.getName());

}

// 创建单级目录

File dir1 = new File("mydir");

if (dir1.mkdir()) {

System.out.println("目录创建成功: " + dir1.getName());

}

// 创建多级目录

File dir2 = new File("a/b/c/d");

if (dir2.mkdirs()) {

System.out.println("多级目录创建成功: " + dir2.getPath());

}

} catch (IOException e) {

e.printStackTrace();

}

// 3. 文件属性获取

System.out.println("\n=== 文件属性 ===");

System.out.println("文件名: " + file1.getName());

System.out.println("绝对路径: " + file1.getAbsolutePath());

System.out.println("规范路径: " + file1.getCanonicalPath());

System.out.println("父目录: " + file1.getParent());

System.out.println("文件大小: " + file1.length() + " bytes");

System.out.println("是否可读: " + file1.canRead());

System.out.println("是否可写: " + file1.canWrite());

System.out.println("是否可执行: " + file1.canExecute());

System.out.println("是否是文件: " + file1.isFile());

System.out.println("是否是目录: " + file1.isDirectory());

System.out.println("是否是隐藏文件: " + file1.isHidden());

long lastModified = file1.lastModified();

Date date = new Date(lastModified);

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

System.out.println("最后修改时间: " + sdf.format(date));

// 4. 文件操作

System.out.println("\n=== 文件操作 ===");

// 重命名

File newFile = new File("test_renamed.txt");

if (file1.renameTo(newFile)) {

System.out.println("文件重命名成功");

}

// 删除文件

if (newFile.delete()) {

System.out.println("文件删除成功");

}

// 5. 目录操作

System.out.println("\n=== 目录操作 ===");

File currentDir = new File(".");

// 列出目录内容

System.out.println("当前目录内容:");

String[] list = currentDir.list();

if (list != null) {

for (String item : list) {

System.out.println(" " + item);

}

}

// 列出文件和目录(带过滤)

System.out.println("\n所有.txt文件:");

File[] txtFiles = currentDir.listFiles((dir, name) -> name.endsWith(".txt"));

if (txtFiles != null) {

for (File f : txtFiles) {

System.out.println(" " + f.getName());

}

}

// 6. 临时文件

try {

File tempFile = File.createTempFile("temp_", ".tmp");

System.out.println("\n临时文件创建: " + tempFile.getAbsolutePath());

// 程序退出时删除临时文件

tempFile.deleteOnExit();

} catch (IOException e) {

e.printStackTrace();

}

}

}

2.2 递归遍历目录

import java.io.File;

import java.util.ArrayList;

import java.util.List;

public class DirectoryTraversal {

/**

* 递归遍历目录,获取所有文件

*/

public static List<File> getAllFiles(File dir) {

List<File> fileList = new ArrayList<>();

traverseDirectory(dir, fileList);

return fileList;

}

private static void traverseDirectory(File dir, List<File> fileList) {

if (dir == null || !dir.exists() || !dir.isDirectory()) {

return;

}

File[] files = dir.listFiles();

if (files == null) {

return;

}

for (File file : files) {

if (file.isFile()) {

fileList.add(file);

} else if (file.isDirectory()) {

traverseDirectory(file, fileList);

}

}

}

/**

* 按文件类型统计

*/

public static void countFilesByType(File dir) {

int totalFiles = 0;

int javaFiles = 0;

int txtFiles = 0;

int otherFiles = 0;

List<File> allFiles = getAllFiles(dir);

for (File file : allFiles) {

totalFiles++;

String name = file.getName().toLowerCase();

if (name.endsWith(".java")) {

javaFiles++;

} else if (name.endsWith(".txt")) {

txtFiles++;

} else {

otherFiles++;

}

}

System.out.println("文件统计:");

System.out.println("总文件数: " + totalFiles);

System.out.println("Java文件: " + javaFiles);

System.out.println("文本文件: " + txtFiles);

System.out.println("其他文件: " + otherFiles);

}

/**

* 查找特定文件

*/

public static List<File> searchFiles(File dir, String keyword) {

List<File> result = new ArrayList<>();

List<File> allFiles = getAllFiles(dir);

for (File file : allFiles) {

if (file.getName().toLowerCase().contains(keyword.toLowerCase())) {

result.add(file);

}

}

return result;

}

/**

* 计算目录大小

*/

public static long calculateDirectorySize(File dir) {

long totalSize = 0;

List<File> allFiles = getAllFiles(dir);

for (File file : allFiles) {

totalSize += file.length();

}

return totalSize;

}

/**

* 格式化文件大小

*/

public static String formatFileSize(long size) {

if (size < 1024) {

return size + " B";

} else if (size < 1024 * 1024) {

return String.format("%.2f KB", size / 1024.0);

} else if (size < 1024 * 1024 * 1024) {

return String.format("%.2f MB", size / (1024.0 * 1024.0));

} else {

return String.format("%.2f GB", size / (1024.0 * 1024.0 * 1024.0));

}

}

public static void main(String[] args) {

System.out.println("=== 目录遍历和操作 ===");

File currentDir = new File(".");

// 获取所有文件

List<File> allFiles = getAllFiles(currentDir);

System.out.println("所有文件 (" + allFiles.size() + "个):");

for (int i = 0; i < Math.min(5, allFiles.size()); i++) {

System.out.println(" " + allFiles.get(i).getPath());

}

if (allFiles.size() > 5) {

System.out.println(" ... 还有 " + (allFiles.size() - 5) + " 个文件");

}

// 文件统计

countFilesByType(currentDir);

// 查找文件

System.out.println("\n查找包含'Test'的文件:");

List<File> searchResults = searchFiles(currentDir, "Test");

for (File file : searchResults) {

System.out.println(" " + file.getName());

}

// 计算目录大小

long dirSize = calculateDirectorySize(currentDir);

System.out.println("\n目录总大小: " + formatFileSize(dirSize));

// 文件树形展示

System.out.println("\n目录树形结构:");

printDirectoryTree(currentDir, 0);

}

private static void printDirectoryTree(File dir, int level) {

if (!dir.exists() || !dir.isDirectory()) {

return;

}

// 打印当前目录

StringBuilder prefix = new StringBuilder();

for (int i = 0; i < level; i++) {

prefix.append(" ");

}

System.out.println(prefix + "├─ " + dir.getName() + "/");

File[] files = dir.listFiles();

if (files == null) {

return;

}

for (int i = 0; i < files.length; i++) {

File file = files[i];

String indent = prefix.toString();

if (i == files.length - 1) {

indent += " └─ ";

} else {

indent += " ├─ ";

}

if (file.isDirectory()) {

System.out.println(indent + file.getName() + "/");

printDirectoryTree(file, level + 2);

} else {

System.out.println(indent + file.getName() +

" (" + formatFileSize(file.length()) + ")");

}

}

}

}

三、字节流(Byte Streams)

3.1 FileInputStream 和 FileOutputStream

import java.io.*;

public class ByteStreamDemo {

/**

* 使用FileInputStream读取文件(逐个字节)

*/

public static void readFileByteByByte(String filePath) {

System.out.println("\n=== 逐个字节读取文件 ===");

try (FileInputStream fis = new FileInputStream(filePath)) {

int byteData;

int count = 0;

while ((byteData = fis.read()) != -1) {

System.out.print((char) byteData);

count++;

if (count % 100 == 0) { // 每100个字符换行显示

System.out.println();

}

}

System.out.println("\n总字节数: " + count);

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 使用缓冲区读取文件(提高效率)

*/

public static void readFileWithBuffer(String filePath) {

System.out.println("\n=== 使用缓冲区读取文件 ===");

try (FileInputStream fis = new FileInputStream(filePath)) {

byte[] buffer = new byte[1024]; // 1KB缓冲区

int bytesRead;

int totalBytes = 0;

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

// 处理读取的数据

String content = new String(buffer, 0, bytesRead);

System.out.print(content);

totalBytes += bytesRead;

}

System.out.println("\n总字节数: " + totalBytes);

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 使用FileOutputStream写入文件

*/

public static void writeFile(String filePath, String content) {

System.out.println("\n=== 写入文件 ===");

try (FileOutputStream fos = new FileOutputStream(filePath)) {

byte[] bytes = content.getBytes();

fos.write(bytes);

System.out.println("写入完成,字节数: " + bytes.length);

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 追加内容到文件

*/

public static void appendToFile(String filePath, String content) {

System.out.println("\n=== 追加内容到文件 ===");

try (FileOutputStream fos = new FileOutputStream(filePath, true)) { // true表示追加模式

byte[] bytes = content.getBytes();

fos.write(bytes);

System.out.println("追加完成,追加字节数: " + bytes.length);

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 文件复制(字节流)

*/

public static void copyFile(String sourcePath, String targetPath) {

System.out.println("\n=== 文件复制 ===");

long startTime = System.currentTimeMillis();

try (FileInputStream fis = new FileInputStream(sourcePath);

FileOutputStream fos = new FileOutputStream(targetPath)) {

byte[] buffer = new byte[8192]; // 8KB缓冲区

int bytesRead;

long totalBytes = 0;

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

fos.write(buffer, 0, bytesRead);

totalBytes += bytesRead;

}

long endTime = System.currentTimeMillis();

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

System.out.println("总字节数: " + totalBytes);

System.out.println("耗时: " + (endTime - startTime) + "ms");

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 读取文件前N个字节

*/

public static byte[] readFirstNBytes(String filePath, int n) {

try (FileInputStream fis = new FileInputStream(filePath)) {

byte[] result = new byte[Math.min(n, fis.available())];

int bytesRead = fis.read(result);

return result;

} catch (IOException e) {

e.printStackTrace();

return new byte[0];

}

}

/**

* 文件加密(简单的XOR加密)

*/

public static void encryptFile(String sourcePath, String targetPath, byte key) {

System.out.println("\n=== 文件加密 ===");

try (FileInputStream fis = new FileInputStream(sourcePath);

FileOutputStream fos = new FileOutputStream(targetPath)) {

int byteData;

while ((byteData = fis.read()) != -1) {

fos.write(byteData ^ key); // XOR加密

}

System.out.println("文件加密完成");

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 文件解密

*/

public static void decryptFile(String sourcePath, String targetPath, byte key) {

System.out.println("\n=== 文件解密 ===");

// 解密和加密使用相同的操作

encryptFile(sourcePath, targetPath, key);

System.out.println("文件解密完成");

}

public static void main(String[] args) {

String testFile = "test.txt";

String copyFile = "test_copy.txt";

String encryptedFile = "test_encrypted.dat";

String decryptedFile = "test_decrypted.txt";

// 创建测试文件

String content = "Hello, Java IO Stream!\n" +

"This is a test file for demonstrating IO operations.\n" +

"字节流可以处理所有类型的数据。\n" +

"Binary data: \u0001\u0002\u0003\u0004\u0005";

writeFile(testFile, content);

// 追加内容

appendToFile(testFile, "\n\nThis is appended content.");

// 读取文件

readFileByteByByte(testFile);

readFileWithBuffer(testFile);

// 复制文件

copyFile(testFile, copyFile);

// 读取文件前N个字节

byte[] firstBytes = readFirstNBytes(testFile, 20);

System.out.println("\n前20个字节: " + new String(firstBytes));

// 文件加密解密

byte encryptionKey = 0x55; // 加密密钥

encryptFile(testFile, encryptedFile, encryptionKey);

decryptFile(encryptedFile, decryptedFile, encryptionKey);

// 清理测试文件

new File(testFile).delete();

new File(copyFile).delete();

new File(encryptedFile).delete();

new File(decryptedFile).delete();

}

}

3.2 缓冲字节流(Buffered)

import java.io.*;

public class BufferedStreamDemo {

/**

* 使用BufferedInputStream提高读取性能

*/

public static void readWithBufferedStream(String filePath) {

System.out.println("\n=== 使用BufferedInputStream读取 ===");

long startTime = System.currentTimeMillis();

try (BufferedInputStream bis = new BufferedInputStream(

new FileInputStream(filePath))) {

byte[] buffer = new byte[1024];

int bytesRead;

long totalBytes = 0;

while ((bytesRead = bis.read(buffer)) != -1) {

totalBytes += bytesRead;

}

long endTime = System.currentTimeMillis();

System.out.println("读取完成,总字节数: " + totalBytes);

System.out.println("耗时: " + (endTime - startTime) + "ms");

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 使用BufferedOutputStream提高写入性能

*/

public static void writeWithBufferedStream(String filePath, String content) {

System.out.println("\n=== 使用BufferedOutputStream写入 ===");

long startTime = System.currentTimeMillis();

try (BufferedOutputStream bos = new BufferedOutputStream(

new FileOutputStream(filePath))) {

byte[] bytes = content.getBytes();

bos.write(bytes);

bos.flush(); // 确保数据写入磁盘

long endTime = System.currentTimeMillis();

System.out.println("写入完成,字节数: " + bytes.length);

System.out.println("耗时: " + (endTime - startTime) + "ms");

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 性能对比测试

*/

public static void performanceTest(String filePath) {

System.out.println("\n=== 性能对比测试 ===");

// 生成测试数据

StringBuilder sb = new StringBuilder();

for (int i = 0; i < 100000; i++) {

sb.append("Line ").append(i).append(": Test data for performance comparison\n");

}

String testData = sb.toString();

// 测试1:普通FileOutputStream

long start1 = System.currentTimeMillis();

try (FileOutputStream fos = new FileOutputStream(filePath + ".test1")) {

fos.write(testData.getBytes());

} catch (IOException e) {

e.printStackTrace();

}

long end1 = System.currentTimeMillis();

// 测试2:BufferedOutputStream

long start2 = System.currentTimeMillis();

try (BufferedOutputStream bos = new BufferedOutputStream(

new FileOutputStream(filePath + ".test2"))) {

bos.write(testData.getBytes());

} catch (IOException e) {

e.printStackTrace();

}

long end2 = System.currentTimeMillis();

System.out.println("普通FileOutputStream耗时: " + (end1 - start1) + "ms");

System.out.println("BufferedOutputStream耗时: " + (end2 - start2) + "ms");

// 清理测试文件

new File(filePath + ".test1").delete();

new File(filePath + ".test2").delete();

}

/**

* 使用mark()和reset()方法

*/

public static void markAndResetDemo(String filePath) {

System.out.println("\n=== mark()和reset()演示 ===");

try (BufferedInputStream bis = new BufferedInputStream(

new FileInputStream(filePath))) {

// 标记当前位置

bis.mark(100); // 参数指定标记失效前可读取的最大字节数

// 读取10个字节

byte[] buffer1 = new byte[10];

bis.read(buffer1);

System.out.println("前10个字节: " + new String(buffer1));

// 重置到标记位置

bis.reset();

// 再次读取

byte[] buffer2 = new byte[10];

bis.read(buffer2);

System.out.println("重置后读取: " + new String(buffer2));

// 跳过部分字节

bis.skip(5);

// 查看剩余可用字节

System.out.println("剩余可用字节: " + bis.available());

} catch (IOException e) {

e.printStackTrace();

}

}

public static void main(String[] args) {

String testFile = "buffer_test.txt";

// 创建测试文件

String content = "This is a test file for buffered stream demonstration.\n" +

"Buffered streams can significantly improve IO performance.\n" +

"They use an internal buffer to reduce the number of actual IO operations.\n";

writeWithBufferedStream(testFile, content);

readWithBufferedStream(testFile);

// mark和reset演示

markAndResetDemo(testFile);

// 性能测试

performanceTest("performance_test");

// 清理测试文件

new File(testFile).delete();

}

}

四、字符流(Character Streams)

4.1 FileReader 和 FileWriter

import java.io.*;

public class CharacterStreamDemo {

/**

* 使用FileReader读取文本文件

*/

public static void readWithFileReader(String filePath) {

System.out.println("\n=== 使用FileReader读取 ===");

try (FileReader reader = new FileReader(filePath)) {

char[] buffer = new char[1024];

int charsRead;

StringBuilder content = new StringBuilder();

while ((charsRead = reader.read(buffer)) != -1) {

content.append(buffer, 0, charsRead);

}

System.out.println("文件内容:");

System.out.println(content);

System.out.println("字符数: " + content.length());

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 使用FileWriter写入文本文件

*/

public static void writeWithFileWriter(String filePath, String content) {

System.out.println("\n=== 使用FileWriter写入 ===");

try (FileWriter writer = new FileWriter(filePath)) {

writer.write(content);

writer.flush();

System.out.println("写入完成,字符数: " + content.length());

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 按行读取文件(自定义实现)

*/

public static void readLineByLine(String filePath) {

System.out.println("\n=== 按行读取文件 ===");

try (FileReader fr = new FileReader(filePath)) {

StringBuilder line = new StringBuilder();

int charCode;

int lineNumber = 1;

while ((charCode = fr.read()) != -1) {

char ch = (char) charCode;

if (ch == '\n') {

System.out.println(lineNumber++ + ": " + line);

line.setLength(0); // 清空StringBuilder

} else if (ch != '\r') {

line.append(ch);

}

}

// 处理最后一行(如果没有换行符结尾)

if (line.length() > 0) {

System.out.println(lineNumber + ": " + line);

}

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 处理字符编码

*/

public static void handleCharacterEncoding(String filePath) {

System.out.println("\n=== 字符编码处理 ===");

// 不同编码的文本

String text = "Hello, 世界! 这是UTF-8编码的文本。";

// 以UTF-8编码写入

try (OutputStreamWriter writer = new OutputStreamWriter(

new FileOutputStream(filePath + ".utf8"), "UTF-8")) {

writer.write(text);

System.out.println("UTF-8编码文件已写入");

} catch (IOException e) {

e.printStackTrace();

}

// 以GBK编码写入

try (OutputStreamWriter writer = new OutputStreamWriter(

new FileOutputStream(filePath + ".gbk"), "GBK")) {

writer.write(text);

System.out.println("GBK编码文件已写入");

} catch (IOException e) {

e.printStackTrace();

}

// 以不同编码读取

System.out.println("\n以不同编码读取文件:");

try (InputStreamReader reader = new InputStreamReader(

new FileInputStream(filePath + ".utf8"), "UTF-8")) {

char[] buffer = new char[1024];

int charsRead = reader.read(buffer);

System.out.println("UTF-8读取: " + new String(buffer, 0, charsRead));

} catch (IOException e) {

e.printStackTrace();

}

try (InputStreamReader reader = new InputStreamReader(

new FileInputStream(filePath + ".gbk"), "GBK")) {

char[] buffer = new char[1024];

int charsRead = reader.read(buffer);

System.out.println("GBK读取: " + new String(buffer, 0, charsRead));

} catch (IOException e) {

e.printStackTrace();

}

// 清理文件

new File(filePath + ".utf8").delete();

new File(filePath + ".gbk").delete();

}

/**

* 字符流复制文本文件(保持格式)

*/

public static void copyTextFile(String sourcePath, String targetPath) {

System.out.println("\n=== 字符流复制文本文件 ===");

try (FileReader reader = new FileReader(sourcePath);

FileWriter writer = new FileWriter(targetPath)) {

char[] buffer = new char[1024];

int charsRead;

long totalChars = 0;

while ((charsRead = reader.read(buffer)) != -1) {

writer.write(buffer, 0, charsRead);

totalChars += charsRead;

}

System.out.println("文件复制完成,总字符数: " + totalChars);

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 统计文本文件信息

*/

public static void analyzeTextFile(String filePath) {

System.out.println("\n=== 文本文件分析 ===");

try (FileReader reader = new FileReader(filePath)) {

int charCode;

int totalChars = 0;

int letters = 0;

int digits = 0;

int spaces = 0;

int lines = 1; // 至少一行

int chineseChars = 0;

while ((charCode = reader.read()) != -1) {

char ch = (char) charCode;

totalChars++;

if (Character.isLetter(ch)) {

letters++;

// 判断是否为中文字符

if (ch >= '\u4e00' && ch <= '\u9fa5') {

chineseChars++;

}

} else if (Character.isDigit(ch)) {

digits++;

} else if (Character.isWhitespace(ch)) {

spaces++;

if (ch == '\n') {

lines++;

}

}

}

System.out.println("总字符数: " + totalChars);

System.out.println("字母数: " + letters);

System.out.println("数字数: " + digits);

System.out.println("空格数: " + spaces);

System.out.println("行数: " + lines);

System.out.println("中文字符数: " + chineseChars);

} catch (IOException e) {

e.printStackTrace();

}

}

public static void main(String[] args) {

String testFile = "char_test.txt";

String copyFile = "char_test_copy.txt";

// 创建测试文件

String content = "Hello, World!\n" +

"这是一个测试文件。\n" +

"用于演示字符流的操作。\n" +

"Line 4: 12345 67890\n" +

"最后一行。";

writeWithFileWriter(testFile, content);

// 读取文件

readWithFileReader(testFile);

// 按行读取

readLineByLine(testFile);

// 字符编码处理

handleCharacterEncoding("encoding_test");

// 复制文件

copyTextFile(testFile, copyFile);

// 分析文件

analyzeTextFile(testFile);

// 清理测试文件

new File(testFile).delete();

new File(copyFile).delete();

}

}

4.2 缓冲字符流(BufferedReader/BufferedWriter)

import java.io.*;

public class BufferedCharacterStreamDemo {

/**

* 使用BufferedReader读取文件

*/

public static void readWithBufferedReader(String filePath) {

System.out.println("\n=== 使用BufferedReader读取 ===");

try (BufferedReader reader = new BufferedReader(

new FileReader(filePath))) {

String line;

int lineNumber = 1;

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

System.out.println(lineNumber++ + ": " + line);

}

System.out.println("总行数: " + (lineNumber - 1));

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 使用BufferedWriter写入文件

*/

public static void writeWithBufferedWriter(String filePath, String[] lines) {

System.out.println("\n=== 使用BufferedWriter写入 ===");

try (BufferedWriter writer = new BufferedWriter(

new FileWriter(filePath))) {

for (String line : lines) {

writer.write(line);

writer.newLine(); // 换行,跨平台

}

writer.flush();

System.out.println("写入完成,行数: " + lines.length);

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 查找包含特定字符串的行

*/

public static void findLinesContaining(String filePath, String keyword) {

System.out.println("\n=== 查找包含 '" + keyword + "' 的行 ===");

try (BufferedReader reader = new BufferedReader(

new FileReader(filePath))) {

String line;

int lineNumber = 1;

int matchCount = 0;

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

if (line.contains(keyword)) {

System.out.println("第" + lineNumber + "行: " + line);

matchCount++;

}

lineNumber++;

}

System.out.println("找到 " + matchCount + " 行匹配内容");

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 复制文件并添加行号

*/

public static void copyFileWithLineNumbers(String sourcePath, String targetPath) {

System.out.println("\n=== 复制文件并添加行号 ===");

try (BufferedReader reader = new BufferedReader(

new FileReader(sourcePath));

BufferedWriter writer = new BufferedWriter(

new FileWriter(targetPath))) {

String line;

int lineNumber = 1;

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

writer.write(String.format("%04d: %s", lineNumber, line));

writer.newLine();

lineNumber++;

}

System.out.println("复制完成,共 " + (lineNumber - 1) + " 行");

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 读取大文件的分页功能

*/

public static void readFileByPage(String filePath, int pageSize) {

System.out.println("\n=== 分页读取文件(每页" + pageSize + "行)===");

try (BufferedReader reader = new BufferedReader(

new FileReader(filePath))) {

String line;

int currentLine = 0;

int pageNumber = 1;

boolean continueReading = true;

while (continueReading) {

System.out.println("\n--- 第 " + pageNumber + " 页 ---");

int linesInPage = 0;

while (linesInPage < pageSize && (line = reader.readLine()) != null) {

System.out.println(line);

linesInPage++;

currentLine++;

}

if (line == null) {

System.out.println("\n已到文件末尾,总行数: " + currentLine);

break;

}

// 模拟用户输入

System.out.print("\n按Enter键继续下一页,输入q退出: ");

BufferedReader consoleReader = new BufferedReader(

new InputStreamReader(System.in));

String input = consoleReader.readLine();

if ("q".equalsIgnoreCase(input.trim())) {

continueReading = false;

}

pageNumber++;

}

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 合并多个文本文件

*/

public static void mergeTextFiles(String[] sourceFiles, String targetFile) {

System.out.println("\n=== 合并多个文本文件 ===");

try (BufferedWriter writer = new BufferedWriter(

new FileWriter(targetFile))) {

for (String sourceFile : sourceFiles) {

System.out.println("正在合并: " + sourceFile);

try (BufferedReader reader = new BufferedReader(

new FileReader(sourceFile))) {

writer.write("=== " + sourceFile + " ===");

writer.newLine();

String line;

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

writer.write(line);

writer.newLine();

}

writer.newLine(); // 文件间空行

}

}

System.out.println("文件合并完成: " + targetFile);

} catch (IOException e) {

e.printStackTrace();

}

}

public static void main(String[] args) {

String testFile = "buffered_char_test.txt";

String numberedFile = "buffered_char_test_numbered.txt";

String[] sourceFiles = {"file1.txt", "file2.txt", "file3.txt"};

String mergedFile = "merged.txt";

// 创建测试文件

String[] lines = {

"第一行: Java IO 流操作",

"第二行: BufferedReader 和 BufferedWriter",

"第三行: 提供缓冲功能,提高效率",

"第四行: 支持 readLine() 方法",

"第五行: 可以按行读取文本文件",

"第六行: 这是最后一行"

};

writeWithBufferedWriter(testFile, lines);

// 读取文件

readWithBufferedReader(testFile);

// 查找包含特定字符串的行

findLinesContaining(testFile, "Buffered");

// 复制文件并添加行号

copyFileWithLineNumbers(testFile, numberedFile);

// 创建用于合并的文件

for (int i = 0; i < sourceFiles.length; i++) {

String[] fileLines = {"文件 " + (i + 1) + " 的内容", "这是第 " + (i + 1) + " 个文件"};

writeWithBufferedWriter(sourceFiles[i], fileLines);

}

// 合并文件

mergeTextFiles(sourceFiles, mergedFile);

// 分页读取演示

System.out.println("\n=== 分页读取演示 ===");

readFileByPage(testFile, 3);

// 清理测试文件

new File(testFile).delete();

new File(numberedFile).delete();

new File(mergedFile).delete();

for (String sourceFile : sourceFiles) {

new File(sourceFile).delete();

}

}

}

五、高级IO操作

5.1 数据流(DataInputStream/DataOutputStream)

import java.io.*;

public class DataStreamDemo {

/**

* 使用DataOutputStream写入各种数据类型

*/

public static void writeWithDataStream(String filePath) {

System.out.println("\n=== 使用DataOutputStream写入 ===");

try (DataOutputStream dos = new DataOutputStream(

new FileOutputStream(filePath))) {

// 写入各种数据类型

dos.writeBoolean(true);

dos.writeByte(65); // 'A'

dos.writeChar('中');

dos.writeShort(1000);

dos.writeInt(123456);

dos.writeLong(9876543210L);

dos.writeFloat(3.14159f);

dos.writeDouble(2.71828);

dos.writeUTF("Hello, 世界!"); // UTF-8编码字符串

System.out.println("数据写入完成");

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 使用DataInputStream读取各种数据类型

*/

public static void readWithDataStream(String filePath) {

System.out.println("\n=== 使用DataInputStream读取 ===");

try (DataInputStream dis = new DataInputStream(

new FileInputStream(filePath))) {

// 读取顺序必须与写入顺序一致

boolean boolValue = dis.readBoolean();

byte byteValue = dis.readByte();

char charValue = dis.readChar();

short shortValue = dis.readShort();

int intValue = dis.readInt();

long longValue = dis.readLong();

float floatValue = dis.readFloat();

double doubleValue = dis.readDouble();

String stringValue = dis.readUTF();

System.out.println("读取的数据:");

System.out.println("boolean: " + boolValue);

System.out.println("byte: " + byteValue + " (char: " + (char)byteValue + ")");

System.out.println("char: " + charValue);

System.out.println("short: " + shortValue);

System.out.println("int: " + intValue);

System.out.println("long: " + longValue);

System.out.println("float: " + floatValue);

System.out.println("double: " + doubleValue);

System.out.println("String: " + stringValue);

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 读写学生信息

*/

public static void writeStudentInfo(String filePath) {

System.out.println("\n=== 写入学生信息 ===");

try (DataOutputStream dos = new DataOutputStream(

new FileOutputStream(filePath))) {

// 写入学生数量

dos.writeInt(3);

// 学生1

dos.writeUTF("张三");

dos.writeInt(20);

dos.writeDouble(89.5);

dos.writeBoolean(true); // 是否及格

// 学生2

dos.writeUTF("李四");

dos.writeInt(22);

dos.writeDouble(76.0);

dos.writeBoolean(true);

// 学生3

dos.writeUTF("王五");

dos.writeInt(19);

dos.writeDouble(59.5);

dos.writeBoolean(false);

System.out.println("学生信息写入完成");

} catch (IOException e) {

e.printStackTrace();

}

}

public static void readStudentInfo(String filePath) {

System.out.println("\n=== 读取学生信息 ===");

try (DataInputStream dis = new DataInputStream(

new FileInputStream(filePath))) {

int studentCount = dis.readInt();

System.out.println("学生人数: " + studentCount);

System.out.println("\n学生信息:");

System.out.println("姓名\t年龄\t成绩\t是否及格");

System.out.println("---------------------------");

for (int i = 0; i < studentCount; i++) {

String name = dis.readUTF();

int age = dis.readInt();

double score = dis.readDouble();

boolean passed = dis.readBoolean();

System.out.printf("%s\t%d\t%.1f\t%s\n",

name, age, score, passed ? "是" : "否");

}

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 处理大端序和小端序

*/

public static void endianDemo() {

System.out.println("\n=== 字节序演示 ===");

int value = 0x12345678;

System.out.println("原始值: 0x" + Integer.toHexString(value));

// Java默认使用大端序(Big-Endian)

ByteArrayOutputStream baos = new ByteArrayOutputStream();

try (DataOutputStream dos = new DataOutputStream(baos)) {

dos.writeInt(value);

} catch (IOException e) {

e.printStackTrace();

}

byte[] bytes = baos.toByteArray();

System.out.print("大端序字节: ");

for (byte b : bytes) {

System.out.printf("%02X ", b);

}

System.out.println();

// 手动转换为小端序

byte[] littleEndian = new byte[4];

for (int i = 0; i < 4; i++) {

littleEndian[i] = bytes[3 - i];

}

System.out.print("小端序字节: ");

for (byte b : littleEndian) {

System.out.printf("%02X ", b);

}

System.out.println();

}

public static void main(String[] args) {

String dataFile = "data_stream_test.dat";

String studentFile = "student_info.dat";

// DataStream读写演示

writeWithDataStream(dataFile);

readWithDataStream(dataFile);

// 学生信息读写

writeStudentInfo(studentFile);

readStudentInfo(studentFile);

// 字节序演示

endianDemo();

// 清理测试文件

new File(dataFile).delete();

new File(studentFile).delete();

}

}

5.2 对象序列化(Object Streams)

import java.io.*;

import java.util.Date;

public class ObjectStreamDemo {

// 可序列化的学生类

static class Student implements Serializable {

// 序列化版本ID,确保序列化兼容性

private static final long serialVersionUID = 1L;

private String name;

private int age;

private transient double score; // transient关键字表示不序列化

private Date birthDate;

public Student(String name, int age, double score, Date birthDate) {

this.name = name;

this.age = age;

this.score = score;

this.birthDate = birthDate;

}

@Override

public String toString() {

return "Student{" +

"name='" + name + '\'' +

", age=" + age +

", score=" + score +

", birthDate=" + birthDate +

'}';

}

}

/**

* 序列化对象到文件

*/

public static void serializeObject(String filePath, Object obj) {

System.out.println("\n=== 序列化对象 ===");

try (ObjectOutputStream oos = new ObjectOutputStream(

new FileOutputStream(filePath))) {

oos.writeObject(obj);

System.out.println("对象序列化完成: " + obj);

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 从文件反序列化对象

*/

public static Object deserializeObject(String filePath) {

System.out.println("\n=== 反序列化对象 ===");

try (ObjectInputStream ois = new ObjectInputStream(

new FileInputStream(filePath))) {

Object obj = ois.readObject();

System.out.println("对象反序列化完成: " + obj);

return obj;

} catch (IOException | ClassNotFoundException e) {

e.printStackTrace();

return null;

}

}

/**

* 序列化多个对象

*/

public static void serializeMultipleObjects(String filePath) {

System.out.println("\n=== 序列化多个对象 ===");

try (ObjectOutputStream oos = new ObjectOutputStream(

new FileOutputStream(filePath))) {

// 写入多个对象

oos.writeObject(new Student("张三", 20, 89.5, new Date()));

oos.writeObject(new Student("李四", 22, 76.0, new Date()));

oos.writeObject(new Student("王五", 19, 59.5, new Date()));

System.out.println("多个对象序列化完成");

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 反序列化多个对象

*/

public static void deserializeMultipleObjects(String filePath) {

System.out.println("\n=== 反序列化多个对象 ===");

try (ObjectInputStream ois = new ObjectInputStream(

new FileInputStream(filePath))) {

System.out.println("读取的对象:");

try {

while (true) {

Object obj = ois.readObject();

System.out.println(" " + obj);

}

} catch (EOFException e) {

// 到达文件末尾

System.out.println("所有对象读取完成");

}

} catch (IOException | ClassNotFoundException e) {

e.printStackTrace();

}

}

/**

* 自定义序列化

*/

static class CustomSerializable implements Serializable {

private static final long serialVersionUID = 1L;

private String data;

private transient String secret; // 不自动序列化

public CustomSerializable(String data, String secret) {

this.data = data;

this.secret = secret;

}

// 自定义序列化逻辑

private void writeObject(ObjectOutputStream oos) throws IOException {

oos.defaultWriteObject(); // 默认序列化

// 对秘密数据加密后再序列化

String encrypted = encrypt(secret);

oos.writeObject(encrypted);

}

// 自定义反序列化逻辑

private void readObject(ObjectInputStream ois)

throws IOException, ClassNotFoundException {

ois.defaultReadObject(); // 默认反序列化

// 解密秘密数据

String encrypted = (String) ois.readObject();

this.secret = decrypt(encrypted);

}

private String encrypt(String text) {

// 简单的加密:字符后移一位

char[] chars = text.toCharArray();

for (int i = 0; i < chars.length; i++) {

chars[i] = (char)(chars[i] + 1);

}

return new String(chars);

}

private String decrypt(String text) {

// 解密:字符前移一位

char[] chars = text.toCharArray();

for (int i = 0; i < chars.length; i++) {

chars[i] = (char)(chars[i] - 1);

}

return new String(chars);

}

@Override

public String toString() {

return "CustomSerializable{" +

"data='" + data + '\'' +

", secret='" + secret + '\'' +

'}';

}

}

/**

* 序列化演示

*/

public static void testCustomSerializable() {

System.out.println("\n=== 自定义序列化演示 ===");

String filePath = "custom_serializable.dat";

CustomSerializable obj = new CustomSerializable("公开数据", "秘密信息");

// 序列化

try (ObjectOutputStream oos = new ObjectOutputStream(

new FileOutputStream(filePath))) {

oos.writeObject(obj);

System.out.println("对象序列化完成: " + obj);

} catch (IOException e) {

e.printStackTrace();

}

// 反序列化

try (ObjectInputStream ois = new ObjectInputStream(

new FileInputStream(filePath))) {

CustomSerializable restored = (CustomSerializable) ois.readObject();

System.out.println("对象反序列化完成: " + restored);

} catch (IOException | ClassNotFoundException e) {

e.printStackTrace();

}

// 清理文件

new File(filePath).delete();

}

/**

* 序列化版本控制

*/

static class VersionedClass implements Serializable {

// 修改类时更新这个版本号

private static final long serialVersionUID = 2L; // 从1L改为2L

private String name;

private int age;

// 新版本添加的字段

private String email; // 这个字段在旧版本中不存在

public VersionedClass(String name, int age, String email) {

this.name = name;

this.age = age;

this.email = email;

}

@Override

public String toString() {

return "VersionedClass{" +

"name='" + name + '\'' +

", age=" + age +

", email='" + email + '\'' +

'}';

}

}

public static void main(String[] args) {

String studentFile = "student.ser";

String multiFile = "multi_objects.ser";

// 单个对象序列化/反序列化

Student student = new Student("张三", 20, 89.5, new Date());

serializeObject(studentFile, student);

Student restoredStudent = (Student) deserializeObject(studentFile);

// 注意:score字段被标记为transient,反序列化后为默认值0.0

System.out.println("原对象: " + student);

System.out.println("恢复的对象: " + restoredStudent);

// 多个对象序列化/反序列化

serializeMultipleObjects(multiFile);

deserializeMultipleObjects(multiFile);

// 自定义序列化演示

testCustomSerializable();

// 清理测试文件

new File(studentFile).delete();

new File(multiFile).delete();

}

}

六、NIO文件操作(Java 7+)

6.1 NIO.2 Files和Paths类

import java.io.IOException;

import java.nio.file.*;

import java.nio.charset.StandardCharsets;

import java.nio.file.attribute.*;

import java.util.List;

import java.util.Set;

import java.util.stream.Stream;

public class NIO2Demo {

/**

* 基本文件操作

*/

public static void basicFileOperations() {

System.out.println("=== NIO.2 基本文件操作 ===");

// 1. 创建Path对象

Path path1 = Paths.get("nio2_test.txt");

Path path2 = Paths.get(".", "subdir", "file.txt");

Path path3 = Paths.get("/Users", "username", "documents", "test.txt");

System.out.println("path1: " + path1);

System.out.println("path2: " + path2.toAbsolutePath());

System.out.println("path2规范化: " + path2.normalize());

// 2. 文件操作

try {

// 创建文件

if (!Files.exists(path1)) {

Files.createFile(path1);

System.out.println("文件创建成功");

}

// 写入文件

String content = "Hello, NIO.2!\n这是第二行。";

Files.write(path1, content.getBytes(StandardCharsets.UTF_8));

// 追加内容

String appendContent = "\n这是追加的内容。";

Files.write(path1, appendContent.getBytes(StandardCharsets.UTF_8),

StandardOpenOption.APPEND);

// 读取文件

byte[] bytes = Files.readAllBytes(path1);

System.out.println("\n文件内容:\n" + new String(bytes));

// 按行读取

List<String> lines = Files.readAllLines(path1, StandardCharsets.UTF_8);

System.out.println("\n按行读取:");

for (int i = 0; i < lines.size(); i++) {

System.out.println("第" + (i + 1) + "行: " + lines.get(i));

}

// 使用Stream API读取

System.out.println("\n使用Stream读取:");

try (Stream<String> stream = Files.lines(path1, StandardCharsets.UTF_8)) {

stream.forEach(System.out::println);

}

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 目录操作

*/

public static void directoryOperations() {

System.out.println("\n=== NIO.2 目录操作 ===");

try {

// 创建目录

Path dir1 = Paths.get("nio2_dir");

if (!Files.exists(dir1)) {

Files.createDirectory(dir1);

System.out.println("目录创建成功: " + dir1);

}

// 创建多级目录

Path multiDir = Paths.get("a", "b", "c");

Files.createDirectories(multiDir);

System.out.println("多级目录创建成功: " + multiDir);

// 遍历目录

System.out.println("\n遍历目录内容:");

try (Stream<Path> stream = Files.list(Paths.get("."))) {

stream.forEach(p -> System.out.println(" " + p.getFileName()));

}

// 深度遍历

System.out.println("\n深度遍历目录:");

try (Stream<Path> stream = Files.walk(Paths.get("."), 2)) {

stream.forEach(p -> {

try {

String type = Files.isDirectory(p) ? "目录" : "文件";

long size = Files.size(p);

System.out.printf(" %s [%s, %d字节]\n",

p, type, size);

} catch (IOException e) {

e.printStackTrace();

}

});

}

// 查找文件

System.out.println("\n查找.java文件:");

try (Stream<Path> stream = Files.find(Paths.get("."),

2,

(path, attrs) ->

attrs.isRegularFile() &&

path.toString().endsWith(".java"))) {

stream.forEach(p -> System.out.println(" " + p));

}

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 文件复制和移动

*/

public static void fileCopyAndMove() {

System.out.println("\n=== 文件复制和移动 ===");

try {

Path source = Paths.get("nio2_test.txt");

Path copy = Paths.get("nio2_test_copy.txt");

Path move = Paths.get("nio2_test_moved.txt");

// 复制文件

Files.copy(source, copy, StandardCopyOption.REPLACE_EXISTING);

System.out.println("文件复制成功");

// 移动文件

Files.move(copy, move, StandardCopyOption.REPLACE_EXISTING);

System.out.println("文件移动成功");

// 比较文件内容

long mismatch = Files.mismatch(source, move);

if (mismatch == -1) {

System.out.println("两个文件内容相同");

} else {

System.out.println("文件内容不同,第一个不同处位置: " + mismatch);

}

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 文件属性操作

*/

public static void fileAttributes() {

System.out.println("\n=== 文件属性操作 ===");

try {

Path path = Paths.get("nio2_test.txt");

// 基本属性

System.out.println("基本文件信息:");

System.out.println("文件大小: " + Files.size(path) + "字节");

System.out.println("是否可读: " + Files.isReadable(path));

System.out.println("是否可写: " + Files.isWritable(path));

System.out.println("是否可执行: " + Files.isExecutable(path));

System.out.println("是否隐藏: " + Files.isHidden(path));

System.out.println("是否符号链接: " + Files.isSymbolicLink(path));

System.out.println("最后修改时间: " + Files.getLastModifiedTime(path));

// 文件所有者

FileOwnerAttributeView ownerView = Files.getFileAttributeView(

path, FileOwnerAttributeView.class);

if (ownerView != null) {

System.out.println("文件所有者: " + ownerView.getOwner().getName());

}

// 文件权限

Set<PosixFilePermission> permissions = null;

try {

permissions = Files.getPosixFilePermissions(path);

System.out.println("文件权限: " + permissions);

} catch (UnsupportedOperationException e) {

System.out.println("不支持POSIX文件权限");

}

// 设置文件属性

Files.setAttribute(path, "dos:hidden", true);

System.out.println("已设置隐藏属性");

// 获取文件类型

String contentType = Files.probeContentType(path);

System.out.println("文件类型: " + contentType);

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 文件监控

*/

public static void fileWatchService() {

System.out.println("\n=== 文件监控 ===");

try {

WatchService watchService = FileSystems.getDefault().newWatchService();

Path dir = Paths.get(".");

// 注册要监控的事件

dir.register(watchService,

StandardWatchEventKinds.ENTRY_CREATE,

StandardWatchEventKinds.ENTRY_MODIFY,

StandardWatchEventKinds.ENTRY_DELETE);

System.out.println("开始监控目录变化(监控5秒)...");

long startTime = System.currentTimeMillis();

while (System.currentTimeMillis() - startTime < 5000) {

WatchKey key = watchService.poll(1000, java.util.concurrent.TimeUnit.MILLISECONDS);

if (key != null) {

for (WatchEvent<?> event : key.pollEvents()) {

WatchEvent.Kind<?> kind = event.kind();

Path fileName = (Path) event.context();

System.out.println("事件: " + kind.name() + ", 文件: " + fileName);

}

// 重置key,继续接收事件

boolean valid = key.reset();

if (!valid) {

System.out.println("监控key失效");

break;

}

}

}

watchService.close();

System.out.println("监控结束");

} catch (IOException | InterruptedException e) {

e.printStackTrace();

}

}

/**

* 临时文件和目录

*/

public static void tempFilesAndDirs() {

System.out.println("\n=== 临时文件和目录 ===");

try {

// 创建临时文件

Path tempFile = Files.createTempFile("nio2_temp_", ".txt");

System.out.println("临时文件: " + tempFile.toAbsolutePath());

// 写入临时文件

Files.write(tempFile, "临时文件内容".getBytes(StandardCharsets.UTF_8));

// 创建临时目录

Path tempDir = Files.createTempDirectory("nio2_temp_dir_");

System.out.println("临时目录: " + tempDir.toAbsolutePath());

// 在临时目录中创建文件

Path fileInTempDir = tempDir.resolve("test.txt");

Files.write(fileInTempDir, "临时目录中的文件".getBytes(StandardCharsets.UTF_8));

// 程序退出时删除临时文件

tempFile.toFile().deleteOnExit();

fileInTempDir.toFile().deleteOnExit();

tempDir.toFile().deleteOnExit();

} catch (IOException e) {

e.printStackTrace();

}

}

public static void main(String[] args) {

// 基本文件操作

basicFileOperations();

// 目录操作

directoryOperations();

// 文件复制和移动

fileCopyAndMove();

// 文件属性

fileAttributes();

// 文件监控

fileWatchService();

// 临时文件

tempFilesAndDirs();

// 清理测试文件

try {

Files.deleteIfExists(Paths.get("nio2_test.txt"));

Files.deleteIfExists(Paths.get("nio2_test_moved.txt"));

Files.deleteIfExists(Paths.get("nio2_dir"));

// 递归删除目录

Files.walk(Paths.get("a"))

.sorted((a, b) -> -a.compareTo(b)) // 先删除文件,再删除目录

.forEach(p -> {

try {

Files.delete(p);

} catch (IOException e) {

// 忽略删除错误

}

});

} catch (IOException e) {

e.printStackTrace();

}

}

}

七、文件操作工具类

7.1 文件工具类实现

import java.io.*;

import java.nio.file.*;

import java.nio.file.attribute.BasicFileAttributes;

import java.security.MessageDigest;

import java.security.NoSuchAlgorithmException;

import java.util.*;

import java.util.zip.*;

public class FileUtils {

/**

* 复制文件或目录

*/

public static void copy(String source, String target) throws IOException {

Path sourcePath = Paths.get(source);

Path targetPath = Paths.get(target);

if (Files.isDirectory(sourcePath)) {

copyDirectory(sourcePath, targetPath);

} else {

copyFile(sourcePath, targetPath);

}

}

private static void copyFile(Path source, Path target) throws IOException {

Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);

}

private static void copyDirectory(Path source, Path target) throws IOException {

if (!Files.exists(target)) {

Files.createDirectories(target);

}

try (Stream<Path> stream = Files.walk(source)) {

stream.forEach(src -> {

try {

Path dest = target.resolve(source.relativize(src));

if (Files.isDirectory(src)) {

if (!Files.exists(dest)) {

Files.createDirectory(dest);

}

} else {

Files.copy(src, dest, StandardCopyOption.REPLACE_EXISTING);

}

} catch (IOException e) {

throw new RuntimeException(e);

}

});

}

}

/**

* 删除文件或目录(递归删除)

*/

public static void delete(String path) throws IOException {

Path filePath = Paths.get(path);

if (Files.isDirectory(filePath)) {

Files.walk(filePath)

.sorted((a, b) -> -a.compareTo(b)) // 先删除文件,再删除目录

.forEach(p -> {

try {

Files.delete(p);

} catch (IOException e) {

// 忽略删除错误

}

});

} else {

Files.deleteIfExists(filePath);

}

}

/**

* 计算文件MD5哈希值

*/

public static String calculateMD5(String filePath) throws IOException, NoSuchAlgorithmException {

MessageDigest md = MessageDigest.getInstance("MD5");

try (InputStream is = Files.newInputStream(Paths.get(filePath))) {

byte[] buffer = new byte[8192];

int bytesRead;

while ((bytesRead = is.read(buffer)) != -1) {

md.update(buffer, 0, bytesRead);

}

}

byte[] digest = md.digest();

StringBuilder sb = new StringBuilder();

for (byte b : digest) {

sb.append(String.format("%02x", b));

}

return sb.toString();

}

/**

* 比较两个文件是否相同

*/

public static boolean compareFiles(String file1, String file2) throws IOException {

Path path1 = Paths.get(file1);

Path path2 = Paths.get(file2);

// 先比较文件大小

if (Files.size(path1) != Files.size(path2)) {

return false;

}

// 比较内容

return Files.mismatch(path1, path2) == -1;

}

/**

* 文件分割

*/

public static void splitFile(String sourceFile, long partSize) throws IOException {

Path source = Paths.get(sourceFile);

long fileSize = Files.size(source);

long parts = (fileSize + partSize - 1) / partSize;

try (InputStream is = Files.newInputStream(source)) {

byte[] buffer = new byte[8192];

for (int i = 1; i <= parts; i++) {

String partName = sourceFile + ".part" + i;

try (OutputStream os = Files.newOutputStream(Paths.get(partName))) {

long bytesRemaining = Math.min(partSize, fileSize - (i - 1) * partSize);

while (bytesRemaining > 0) {

int bytesToRead = (int) Math.min(buffer.length, bytesRemaining);

int bytesRead = is.read(buffer, 0, bytesToRead);

if (bytesRead == -1) {

break;

}

os.write(buffer, 0, bytesRead);

bytesRemaining -= bytesRead;

}

}

System.out.println("创建分片: " + partName);

}

}

}

/**

* 文件合并

*/

public static void mergeFiles(String[] partFiles, String targetFile) throws IOException {

try (OutputStream os = Files.newOutputStream(Paths.get(targetFile))) {

for (String partFile : partFiles) {

try (InputStream is = Files.newInputStream(Paths.get(partFile))) {

byte[] buffer = new byte[8192];

int bytesRead;

while ((bytesRead = is.read(buffer)) != -1) {

os.write(buffer, 0, bytesRead);

}

}

}

}

}

/**

* 文件压缩(ZIP格式)

*/

public static void compressToZip(String source, String zipFile) throws IOException {

Path sourcePath = Paths.get(source);

try (ZipOutputStream zos = new ZipOutputStream(

new FileOutputStream(zipFile))) {

if (Files.isDirectory(sourcePath)) {

Files.walk(sourcePath)

.filter(path -> !Files.isDirectory(path))

.forEach(path -> {

try {

String entryName = sourcePath.relativize(path).toString();

ZipEntry entry = new ZipEntry(entryName);

zos.putNextEntry(entry);

Files.copy(path, zos);

zos.closeEntry();

} catch (IOException e) {

throw new RuntimeException(e);

}

});

} else {

ZipEntry entry = new ZipEntry(sourcePath.getFileName().toString());

zos.putNextEntry(entry);

Files.copy(sourcePath, zos);

zos.closeEntry();

}

}

}

/**

* 文件解压缩

*/

public static void extractZip(String zipFile, String targetDir) throws IOException {

Path targetPath = Paths.get(targetDir);

try (ZipInputStream zis = new ZipInputStream(

new FileInputStream(zipFile))) {

ZipEntry entry;

while ((entry = zis.getNextEntry()) != null) {

Path entryPath = targetPath.resolve(entry.getName());

// 防止路径遍历攻击

if (!entryPath.normalize().startsWith(targetPath.normalize())) {

throw new IOException("无效的ZIP条目: " + entry.getName());

}

if (entry.isDirectory()) {

Files.createDirectories(entryPath);

} else {

Files.createDirectories(entryPath.getParent());

Files.copy(zis, entryPath, StandardCopyOption.REPLACE_EXISTING);

}

zis.closeEntry();

}

}

}

/**

* 文件搜索

*/

public static List<Path> searchFiles(String directory, String pattern) throws IOException {

List<Path> results = new ArrayList<>();

Path dir = Paths.get(directory);

if (!Files.exists(dir) || !Files.isDirectory(dir)) {

return results;

}

// 使用Files.walk搜索文件

try (Stream<Path> stream = Files.walk(dir)) {

stream.filter(path -> {

String fileName = path.getFileName().toString();

return fileName.toLowerCase().contains(pattern.toLowerCase());

}).forEach(results::add);

}

return results;

}

/**

* 文件编码转换

*/

public static void convertEncoding(String sourceFile, String targetFile,

String sourceCharset, String targetCharset) throws IOException {

try (BufferedReader reader = new BufferedReader(

new InputStreamReader(new FileInputStream(sourceFile), sourceCharset));

BufferedWriter writer = new BufferedWriter(

new OutputStreamWriter(new FileOutputStream(targetFile), targetCharset))) {

String line;

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

writer.write(line);

writer.newLine();

}

}

}

/**

* 统计目录信息

*/

public static class DirectoryInfo {

public long fileCount;

public long directoryCount;

public long totalSize;

public Map<String, Long> sizeByExtension = new HashMap<>();

}

public static DirectoryInfo getDirectoryInfo(String directory) throws IOException {

DirectoryInfo info = new DirectoryInfo();

Path dir = Paths.get(directory);

if (!Files.exists(dir) || !Files.isDirectory(dir)) {

return info;

}

Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {

@Override

public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {

if (!dir.equals(DirectoryInfo.this)) {

info.directoryCount++;

}

return FileVisitResult.CONTINUE;

}

@Override

public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {

info.fileCount++;

info.totalSize += attrs.size();

// 统计文件扩展名

String fileName = file.getFileName().toString();

int dotIndex = fileName.lastIndexOf('.');

if (dotIndex > 0) {

String extension = fileName.substring(dotIndex + 1).toLowerCase();

info.sizeByExtension.merge(extension, attrs.size(), Long::sum);

}

return FileVisitResult.CONTINUE;

}

});

return info;

}

/**

* 监控文件变化

*/

public static void monitorFile(String filePath, FileChangeListener listener) {

Path path = Paths.get(filePath);

if (!Files.exists(path)) {

System.out.println("文件不存在: " + filePath);

return;

}

Thread monitorThread = new Thread(() -> {

try {

long lastModified = Files.getLastModifiedTime(path).toMillis();

long lastSize = Files.size(path);

while (!Thread.currentThread().isInterrupted()) {

Thread.sleep(1000); // 每秒检查一次

if (!Files.exists(path)) {

listener.onFileDeleted();

break;

}

long currentModified = Files.getLastModifiedTime(path).toMillis();

long currentSize = Files.size(path);

if (currentModified != lastModified) {

if (currentSize != lastSize) {

listener.onFileModified();

} else {

listener.onFileTouched();

}

lastModified = currentModified;

lastSize = currentSize;

}

}

} catch (IOException | InterruptedException e) {

// 线程被中断

}

});

monitorThread.setDaemon(true);

monitorThread.start();

}

interface FileChangeListener {

void onFileModified();

void onFileTouched();

void onFileDeleted();

}

public static void main(String[] args) {

try {

// 创建测试文件

String testFile = "test_utils.txt";

Files.write(Paths.get(testFile), "测试内容".getBytes(StandardCharsets.UTF_8));

// 计算MD5

String md5 = calculateMD5(testFile);

System.out.println("文件MD5: " + md5);

// 文件分割

splitFile(testFile, 1024); // 1KB分片

// 搜索文件

List<Path> searchResults = searchFiles(".", "utils");

System.out.println("搜索结果: " + searchResults.size());

// 获取目录信息

DirectoryInfo info = getDirectoryInfo(".");

System.out.println("目录信息:");

System.out.println(" 文件数: " + info.fileCount);

System.out.println(" 目录数: " + info.directoryCount);

System.out.println(" 总大小: " + info.totalSize);

// 监控文件变化

monitorFile(testFile, new FileChangeListener() {

@Override

public void onFileModified() {

System.out.println("文件被修改");

}

@Override

public void onFileTouched() {

System.out.println("文件被访问");

}

@Override

public void onFileDeleted() {

System.out.println("文件被删除");

}

});

// 等待一会儿以便观察监控效果

Thread.sleep(3000);

// 修改文件

Files.write(Paths.get(testFile),

"修改后的内容".getBytes(StandardCharsets.UTF_8),

StandardOpenOption.TRUNCATE_EXISTING);

Thread.sleep(1000);

// 清理测试文件

delete(testFile);

// 删除分片文件

for (int i = 1; ; i++) {

String partFile = testFile + ".part" + i;

if (!Files.exists(Paths.get(partFile))) {

break;

}

delete(partFile);

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

八、最佳实践和性能优化

8.1 IO操作最佳实践

import java.io.*;

import java.nio.file.Files;

import java.nio.file.Paths;

import java.nio.file.StandardOpenOption;

public class IOBestPractices {

/**

* 1. 使用try-with-resources确保资源关闭

*/

public static void practice1_tryWithResources() {

System.out.println("=== 最佳实践1:使用try-with-resources ===");

// 正确做法

try (BufferedReader reader = new BufferedReader(

new FileReader("test.txt"))) {

String line = reader.readLine();

System.out.println("读取内容: " + line);

} catch (IOException e) {

e.printStackTrace();

}

// 错误做法(可能忘记关闭资源)

/*

BufferedReader reader = null;

try {

reader = new BufferedReader(new FileReader("test.txt"));

String line = reader.readLine();

System.out.println("读取内容: " + line);

} catch (IOException e) {

e.printStackTrace();

} finally {

if (reader != null) {

try {

reader.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

*/

}

/**

* 2. 选择合适的缓冲区大小

*/

public static void practice2_bufferSize() throws IOException {

System.out.println("\n=== 最佳实践2:选择合适的缓冲区大小 ===");

String testFile = "large_file.txt";

createLargeFile(testFile, 10 * 1024 * 1024); // 创建10MB文件

long[] times = new long[5];

int[] bufferSizes = {512, 1024, 4096, 8192, 16384};

for (int i = 0; i < bufferSizes.length; i++) {

long startTime = System.currentTimeMillis();

copyFileWithBuffer(testFile, "copy_" + i + ".txt", bufferSizes[i]);

long endTime = System.currentTimeMillis();

times[i] = endTime - startTime;

System.out.printf("缓冲区 %5d bytes: %4d ms\n", bufferSizes[i], times[i]);

}

// 清理测试文件

Files.deleteIfExists(Paths.get(testFile));

for (int i = 0; i < bufferSizes.length; i++) {

Files.deleteIfExists(Paths.get("copy_" + i + ".txt"));

}

}

private static void createLargeFile(String filePath, long size) throws IOException {

try (BufferedWriter writer = new BufferedWriter(

new FileWriter(filePath))) {

for (long i = 0; i < size / 100; i++) {

writer.write("01234567890123456789012345678901234567890123456789");

writer.write("01234567890123456789012345678901234567890123456789\n");

}

}

}

private static void copyFileWithBuffer(String source, String target, int bufferSize)

throws IOException {

try (InputStream is = new FileInputStream(source);

OutputStream os = new FileOutputStream(target)) {

byte[] buffer = new byte[bufferSize];

int bytesRead;

while ((bytesRead = is.read(buffer)) != -1) {

os.write(buffer, 0, bytesRead);

}

}

}

/**

* 3. 使用NIO Files类简化操作

*/

public static void practice3_useNIOFiles() throws IOException {

System.out.println("\n=== 最佳实践3:使用NIO Files类 ===");

String source = "nio_source.txt";

String target = "nio_target.txt";

// 写入文件(一行代码)

Files.writeString(Paths.get(source),

"使用NIO Files类简化文件操作\n第二行内容",

StandardOpenOption.CREATE);

// 读取文件(一行代码)

String content = Files.readString(Paths.get(source));

System.out.println("读取内容:\n" + content);

// 复制文件(一行代码)

Files.copy(Paths.get(source), Paths.get(target));

// 删除文件

Files.deleteIfExists(Paths.get(source));

Files.deleteIfExists(Paths.get(target));

}

/**

* 4. 正确处理字符编码

*/

public static void practice4_characterEncoding() {

System.out.println("\n=== 最佳实践4:正确处理字符编码 ===");

String testFile = "encoding_test.txt";

String content = "Hello, 世界! 中文测试。";

try {

// 错误做法:使用平台默认编码

// Files.writeString(Paths.get(testFile), content);

// 正确做法:明确指定编码

Files.writeString(Paths.get(testFile), content,

java.nio.charset.StandardCharsets.UTF_8);

// 读取时也要指定相同的编码

String readContent = Files.readString(Paths.get(testFile),

java.nio.charset.StandardCharsets.UTF_8);

System.out.println("写入和读取的内容: " + readContent);

// 检测文件编码

String detectedEncoding = detectFileEncoding(testFile);

System.out.println("检测到的编码: " + detectedEncoding);

Files.deleteIfExists(Paths.get(testFile));

} catch (IOException e) {

e.printStackTrace();

}

}

private static String detectFileEncoding(String filePath) throws IOException {

// 简单检测UTF-8 BOM

try (InputStream is = new FileInputStream(filePath)) {

byte[] bom = new byte[3];

int bytesRead = is.read(bom);

if (bytesRead >= 3 &&

bom[0] == (byte)0xEF &&

bom[1] == (byte)0xBB &&

bom[2] == (byte)0xBF) {

return "UTF-8 with BOM";

}

return "UTF-8 (without BOM)";

}

}

/**

* 5. 处理大文件时使用流式处理

*/

public static void practice5_streamProcessing() throws IOException {

System.out.println("\n=== 最佳实践5:流式处理大文件 ===");

String largeFile = "large_data.txt";

// 生成大文件

try (BufferedWriter writer = new BufferedWriter(

new FileWriter(largeFile))) {

for (int i = 0; i < 100000; i++) {

writer.write("Line " + i + ": " +

"This is some data for line " + i + "\n");

}

}

// 流式处理(避免一次性加载到内存)

long lineCount = 0;

long wordCount = 0;

try (BufferedReader reader = new BufferedReader(

new FileReader(largeFile))) {

String line;

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

lineCount++;

wordCount += line.split("\\s+").length;

// 可以在这里处理每一行,而不需要整个文件内容

if (lineCount % 10000 == 0) {

System.out.println("已处理 " + lineCount + " 行");

}

}

}

System.out.println("总行数: " + lineCount);

System.out.println("总单词数: " + wordCount);

Files.deleteIfExists(Paths.get(largeFile));

}

/**

* 6. 使用合适的异常处理

*/

public static void practice6_exceptionHandling() {

System.out.println("\n=== 最佳实践6:合适的异常处理 ===");

String filePath = "nonexistent.txt";

try {

// 尝试读取不存在的文件

String content = Files.readString(Paths.get(filePath));

System.out.println(content);

} catch (java.nio.file.NoSuchFileException e) {

System.out.println("文件不存在: " + e.getFile());

// 创建文件或提供默认值

} catch (java.nio.file.AccessDeniedException e) {

System.out.println("没有访问权限: " + e.getFile());

} catch (IOException e) {

System.out.println("IO错误: " + e.getMessage());

e.printStackTrace();

} finally {

System.out.println("异常处理完成");

}

}

/**

* 7. 文件操作事务性处理

*/

public static void practice7_transactionalFileOperation() {

System.out.println("\n=== 最佳实践7:事务性文件操作 ===");

String tempFile = "data.tmp";

String finalFile = "data.txt";

try {

// 1. 写入临时文件

Files.writeString(Paths.get(tempFile),

"这是要写入的数据\n第二行",

StandardOpenOption.CREATE);

// 2. 验证数据(可以添加校验逻辑)

String tempContent = Files.readString(Paths.get(tempFile));

if (!tempContent.contains("数据")) {

throw new IOException("数据验证失败");

}

// 3. 原子性地重命名为最终文件

Files.move(Paths.get(tempFile), Paths.get(finalFile),

java.nio.file.StandardCopyOption.ATOMIC_MOVE,

java.nio.file.StandardCopyOption.REPLACE_EXISTING);

System.out.println("文件操作成功完成");

// 读取最终文件验证

String finalContent = Files.readString(Paths.get(finalFile));

System.out.println("最终文件内容:\n" + finalContent);

// 清理

Files.deleteIfExists(Paths.get(finalFile));

} catch (IOException e) {

System.out.println("操作失败: " + e.getMessage());

// 清理临时文件

try {

Files.deleteIfExists(Paths.get(tempFile));

} catch (IOException ex) {

// 忽略清理错误

}

}

}

public static void main(String[] args) throws IOException {

practice1_tryWithResources();

practice2_bufferSize();

practice3_useNIOFiles();

practice4_characterEncoding();

practice5_streamProcessing();

practice6_exceptionHandling();

practice7_transactionalFileOperation();

}

}

总结

核心知识点:

  1. File类:文件和目录的基本操作

  2. 字节流:FileInputStream/FileOutputStream,处理二进制数据

  3. 字符流:FileReader/FileWriter,处理文本数据

  4. 缓冲流:BufferedInputStream/BufferedOutputStream/BufferedReader/BufferedWriter,提高IO性能

  5. 数据流:DataInputStream/DataOutputStream,读写基本数据类型

  6. 对象流:ObjectInputStream/ObjectOutputStream,对象序列化

  7. NIO.2:Files和Paths类,更现代的文件操作API

最佳实践:

  1. 使用try-with-resources:确保资源正确关闭

  2. 合理选择缓冲区大小:通常8KB是最佳选择

  3. 明确指定字符编码:避免平台依赖问题

  4. 使用NIO Files类:简化常见文件操作

  5. 流式处理大文件:避免内存溢出

  6. 事务性文件操作:使用临时文件和原子操作

  7. 适当的异常处理:提供用户友好的错误信息

性能优化建议:

  1. 使用缓冲流:显著提高IO性能

  2. 批量读写:避免单字节操作

  3. 选择合适的流类型:文本用字符流,二进制用字节流

  4. 使用NIO通道:对于大文件或高性能要求场景

  5. 异步IO:Java NIO.2支持异步文件操作

相关推荐
Vic101012 小时前
Spring AOP 常用注解完全指南
java·后端·spring
历程里程碑2 小时前
滑动窗口解法:无重复字符最长子串
数据结构·c++·算法·leetcode·职场和发展·eclipse·哈希算法
Geoffwo2 小时前
归一化简单案例
算法·语言模型
FL16238631292 小时前
VTK源码编译时候选qt5路径
开发语言·qt
Felven2 小时前
C. Maximum Median
c语言·开发语言·算法
love530love2 小时前
Windows 下 Z-Image-Turbo 专业版 Gradio 生成器实战:功能增强全记录
人工智能·windows·python·大模型·gradio·博客之星·z-image
CryptoRzz2 小时前
StockTV API 对接全攻略(股票、期货、IPO)
java·javascript·git·web3·区块链·github
iReachers2 小时前
为什么HTML打包安卓APP安装时会覆盖或者报错?
android·java·html·html打包apk·网页打包
纟 冬2 小时前
Flutter & OpenHarmony 运动App运动模式选择组件开发
android·java·flutter