NIO+正则实战🔥 搞定文件IO与文本清洗,新手也能直接上手
核心速通:精简实用,保留核心知识点和可复制代码,新增多样样式,新手快速上手避坑,无需死记硬背
Java开发常遇3大痛点,无需死磕:读取大文件OOM、跨平台路径报错、文本提取清洗繁琐。NIO+正则就是“万能钥匙”,全程实战无废话,代码复制就能用,看完轻松拿捏。
先划重点:吃透NIO核心用法+分清NIO与BIO适用场景;掌握Pattern/Matcher实战技巧,文本处理秒速搞定,省出时间摸鱼不香吗?
不啰嗦,直接开冲!先搞定文件IO的“重灾区”——NIO,再轻松拿捏正则。
一、NIO核心概念详解:告别BIO低效,解锁高效新姿势
NIO(非阻塞IO)是BIO的升级版,核心优势:非阻塞、面向缓冲区/通道,解决BIO线程阻塞的痛点。用大白话讲:BIO是“排队等奶茶”(线程卡死),NIO是“取号后自由活动”(线程可处理其他任务),效率翻倍。
重点拆解4个核心组件,结合可复制代码,懂用法就够了:
1. Path:路径神器(替代File类)
自动适配Windows/Linux路径分隔符,拼接、解析简洁,仅表示路径,操作文件需配合Files类。
import java.nio.file.Path;
import java.nio.file.Paths;
public class PathDemo {
public static void main(String[] args) {
Path absolutePath = Paths.get("D:/test.txt"); // 绝对路径
Path relativePath = Paths.get("src", "main", "resources"); // 相对路径
System.out.println("文件名:" + absolutePath.getFileName());
System.out.println("路径拼接:" + relativePath.resolve("config.properties"));
}
}
2. Files:文件操作万能工具
静态方法一键搞定文件CRUD,避免冗余代码,减少异常踩坑,新手首选。
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.charset.StandardCharsets;
import java.util.List;
public class FilesDemo {
public static void main(String[] args) throws Exception {
Path path = Paths.get("test.txt");
if (!Files.exists(path)) Files.createFile(path); // 不存在则创建
Files.write(path, "Hello NIO".getBytes(StandardCharsets.UTF_8)); // 写入(防乱码)
List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8); // 读取
Files.copy(path, Paths.get("test_copy.txt")); // 复制
Files.deleteIfExists(path); // 存在则删除
}
}
3. ByteBuffer:NIO核心数据容器
重点记:3个指针(position/limit/capacity)+3个方法(flip()/rewind()/clear()),写一遍就懂!
import java.nio.ByteBuffer;
public class ByteBufferDemo {
public static void main(String[] args) {
ByteBuffer buffer = ByteBuffer.allocate(10); // 非直接缓冲区
buffer.put("abc".getBytes()); // 写模式
buffer.flip(); // 写转读,避免读多数据
byte[] dst = new byte[buffer.remaining()]; // 获取可读取字节数
buffer.get(dst);
System.out.println(new String(dst)); // 输出:abc
buffer.clear(); // 清空指针,准备重新写入
}
}
4. Channels:双向数据传输管道
替代BIO单向流,支持双向传输+非阻塞,常用FileChannel处理文件读写,效率更高。
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class ChannelDemo {
public static void main(String[] args) throws Exception {
RandomAccessFile file = new RandomAccessFile("test_channel.txt", "rw");
FileChannel channel = file.getChannel();
// 写入:缓冲区->通道->文件
ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
writeBuffer.put("Hello Channel".getBytes());
writeBuffer.flip();
channel.write(writeBuffer);
// 读取:文件->通道->缓冲区
channel.position(0);
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
int readBytes = channel.read(readBuffer);
System.out.println(new String(readBuffer.array(), 0, readBytes));
// 关闭资源(避免泄漏)
channel.close();
file.close();
}
}
二、关键避坑:NIO和BIO适用场景速查
NIO不是“万能的”,找对场景才高效,对照下表直接用:
✅ 优先用NIO
- 大文件/高并发文件操作(避免OOM)
- 高并发网络编程(如网关、RPC,Netty基础)
- 异步IO、跨平台路径操作
❌ 不适合用NIO
- 小文件读写(如配置文件,BIO更简洁)
- 低并发场景(BIO编程简单,易调试)
三、进阶实战:Files.lines() 处理大文件(告别OOM)
核心优势:懒加载模式,逐行读取释放内存,配合try-with-resources自动关闭资源,杜绝OOM!
3个常用场景,代码直接复制运行:
场景1:基础逐行读取
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;
public class LargeFileStreamDemo {
public static void main(String[] args) {
try (Stream<String> lines = Files.lines(Paths.get("large_file.txt"))) {
lines.forEach(line -> {
// 替换为你的业务逻辑(如解析日志)
System.out.println("处理行:" + line);
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
场景2:过滤统计(贴近业务)
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Optional;
import java.util.stream.Stream;
public class LargeFileAdvancedDemo {
public static void main(String[] args) {
try (Stream<String> lines = Files.lines(Paths.get("large_file.txt"))) {
// 统计ERROR行数+找出第一行错误日志
long errorCount = lines.filter(line -> line.contains("ERROR")).count();
System.out.println("错误行总数:" + errorCount);
// Stream只能消费一次,需重新获取
try (Stream<String> lines2 = Files.lines(Paths.get("large_file.txt"))) {
Optional<String> firstError = lines2.filter(line -> line.contains("ERROR")).findFirst();
firstError.ifPresent(line -> System.out.println("第一行错误:" + line));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
场景3:超大文件并行处理(加速)
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;
public class LargeFileParallelDemo {
public static void main(String[] args) {
try (Stream<String> lines = Files.lines(Paths.get("super_large_file.txt"))) {
// 并行流加速,统计WARN行数(保证业务线程安全)
long warnCount = lines.parallel().filter(line -> line.startsWith("WARN")).count();
System.out.println("警告行总数:" + warnCount);
} catch (Exception e) {
e.printStackTrace();
}
}
}
避坑提醒
- Stream只能消费一次,多次处理需重新获取
- 指定UTF-8编码(Files.lines(Paths.get(path), StandardCharsets.UTF_8)),避免乱码
四、正则实战:Pattern/Matcher 秒搞定文本处理
正则不用死记语法,掌握核心类+常用模板,80%场景直接套用。核心:Pattern(预编译模板)、Matcher(执行匹配)。
3个实战场景(代码可直接复制)
场景1:提取结构化数据(手机号、邮箱、URL)
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexExtractDemo {
public static void main(String[] args) {
String rawText = "联系:13812345678,邮箱:test@example.com,官网:https://www.xxx.com";
// 提取手机号(11位,以1开头)
Pattern phonePattern = Pattern.compile("1[3-9]\d{9}");
Matcher phoneMatcher = phonePattern.matcher(rawText);
while (phoneMatcher.find()) System.out.println("手机号:" + phoneMatcher.group());
// 提取邮箱
Pattern emailPattern = Pattern.compile("\w+@\w+\.\w+");
Matcher emailMatcher = emailPattern.matcher(rawText);
if (emailMatcher.find()) System.out.println("邮箱:" + emailMatcher.group());
// 分组提取URL(协议+域名)
Pattern urlPattern = Pattern.compile("(https?)://([a-zA-Z0-9.]+)");
Matcher urlMatcher = urlPattern.matcher(rawText);
if (urlMatcher.find()) {
System.out.println("协议:" + urlMatcher.group(1) + ",域名:" + urlMatcher.group(2));
}
}
}
场景2:文本清洗(去除无用字符)
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexCleanDemo {
public static void main(String[] args) {
String dirtyText = " 2026-03-22 [ERROR] | 接口超时!\t错误码:500 ### 原因:超时 ### ";
// 步骤1:去除空白字符(空格、制表符)
String step1 = Pattern.compile("\s+").matcher(dirtyText).replaceAll(" ");
// 步骤2:去除###及前后空格
String step2 = Pattern.compile("\s*###\s*").matcher(step1).replaceAll(" ");
// 步骤3:标准化格式(去首尾空格+合并连续空格)
String finalClean = step2.trim().replaceAll("\s+", " ");
System.out.println("清洗后:" + finalClean);
}
}
场景3:大文件正则清洗(NIO+正则结合)
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.regex.Pattern;
import java.util.stream.Stream;
public class LargeFileRegexClean {
// 预编译正则(复用提升性能,别写循环里)
private static final Pattern CLEAN_PATTERN = Pattern.compile("[^a-zA-Z0-9\u4e00-\u9fa5,:。!?\s]");
public static void main(String[] args) {
try (Stream<String> lines = Files.lines(Paths.get("dirty_large_file.txt"), StandardCharsets.UTF_8)) {
Stream<String> cleanLines = lines
.map(line -> CLEAN_PATTERN.matcher(line).replaceAll("")) // 去除非法字符
.map(line -> line.trim().replaceAll("\s+", " ")) // 标准化
.filter(line -> !line.isEmpty()); // 过滤空行
// 写入新文件
Files.write(Paths.get("clean_large_file.txt"), (Iterable<String>) cleanLines::iterator, StandardCharsets.UTF_8);
System.out.println("大文件清洗完成!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
常用正则模板(直接复用):
手机号:1[3-9]\d{9} | 邮箱:\w+@\w+\.(com|cn|net) | 中文:[\u4e00-\u9fa5] | 数字:\d+
正则避坑技巧
- Pattern预编译为静态常量,避免循环内重复编译,提升性能
- 分组捕获用(),group(0)是完整匹配,group(1)是第一个分组
- 贪婪匹配(.)vs 非贪婪匹配(.?),提取标签内容用非贪婪匹配
五、总结(速通重点)
- NIO核心:Path+Files+ByteBuffer+Channel,搞定文件IO所有痛点,避免OOM和跨平台报错
- 场景适配:大文件/高并发用NIO,小文件/低并发用BIO,不盲目追求“高效”
- 正则实战:Pattern预编译+Matcher匹配,掌握常用模板,文本处理秒速搞定
- 关键避坑:Files.lines()懒加载、Stream仅消费一次、正则预编译
技术在于实战,把代码复制下来动手敲一遍,很快就能掌握,看完就忘不如实操!