简介:《RenameFile.java》是一份用Java语言编写的文件批量重命名工具源码,面向需要整理大量文件或目录的Java开发者,也适合刚接触自动化文件操作的学习者。源码基于JDK自带的File类与java.nio.file包:程序接收目录路径作为入参,利用listFiles()获取文件列表后进入循环,在循环体内按既定规则生成新名称,再通过Files.move()配合StandardCopyOption.REPLACE_EXISTING完成跨文件系统的可靠重命名,避免了renameTo()在部分场景下失效的隐患。同时内嵌添加序号、替换名称片段等常见命名策略,并预留自定义规则扩展位置;文件已存在、无权限等异常均在catch块中统一捕获并打印堆栈,便于快速定位问题。整个rar压缩包仅含1个java源文件,包体积约1KB,代码紧凑无冗余。目前已有574人学习下载。借助这份源码可掌握目录遍历、目标路径构造、异常处理等关键写法,理解Java标准IO与NIO在批量重命名中的典型配合,并可迁移到日志整理、照片序列改名、测试数据清理等实践中,是一份参考与工具兼具的轻量示例。
1. 文件批量重命名:从“手动改几小时”到“按钮一点”
你从网盘批量导出的文件,名字总是带一串乱码和广告后缀;你从某公司系统导出的报表,文件名清一色的report_2024_xxx_v2(1).xlsx;你的照片库里有几百张IMG_20240101_123456.jpg要按日期重排——面对这种场景,手动一个个按 F2 改名的滋味,经历过的人都懂。这个 Java 项目要解决的就是这件事:一个带预览界面的批量重命名工具,通过正则替换、序号填充、大小写切换这几类规则,把“逐个右键重命名”变成“选规则→预览→一键执行”。它适合两类人:不想装破解版付费小工具的普通用户,以及想看懂规则引擎和文件操作怎么结合、准备自己造轮子的 Java 开发者。项目本身不复杂,核心就是一个 Swing 窗口加一套规则解析器,但它把文件扫描、规则匹配、操作回滚这几个环节做得非常清晰。
2. 技术选型与整体架构:Swing 界面、规则引擎、文件操作三层怎么拆
2.1 为什么用 Swing 而不是 JavaFX
看到这个项目的第一眼,你可能会问:都什么年代了,怎么还在用 Swing?说实话,这里选 Swing 是比较务实的选择——JDK 自带,无需额外引入运行时依赖,打包出来的 jar 体积小,双击就能跑。JavaFX 虽然界面更漂亮,但 Java 8 之后它从 JDK 里拆出去了,使用时要额外引入模块,这对一个工具型小项目来说反而增加了分发成本。
从项目实现上看,这个重命名工具的交互并不复杂:左侧一个文件列表,右侧一堆规则配置项,中间一个预览区域。Swing 的JTable、JFileChooser、JTextArea完全够用,开发速度快,老技术栈也有它的用武之地。当然,前提是你别拿它和现代前端框架比界面效果。
2.2 三层架构:界面层、规则层、文件层
整个项目按职责拆成了三层,彼此之间通过接口交互,这也是我拿到源码后最先关注的地方。界面层(ui)只负责收集用户操作和展示结果,不碰任何文件读写逻辑;规则层(rule)定义了一组RenameRule接口,每个具体规则(正则替换、序号填充、大小写转换)都是这个接口的一个实现;文件层(file)负责扫描目录、检查文件占用状态、执行物理重命名操作。
为什么要这样拆?因为重命名这个动作本身很简单,但规则的扩展性很重要。今天你可能只需要正则替换,明天就想按文件的创建日期来命名,后天可能想从 Excel 里读映射表。如果规则和文件操作耦合在一起,每次加需求都要动核心类。拆成三层之后,新增一种规则只需要实现RenameRule接口再在界面上注册一下,文件层完全不用改。
抛开高大上的概念,这套设计说白了就是“界面不碰文件,文件不懂规则”。我曾见过不少类似的工具项目,把重命名的逻辑全部堆在按钮的 ActionListener 里,结果代码写到后面一个方法几百行,换个格式就要动一堆代码。这个项目用接口把变化隔离出来,是值得参考的做法。
2.3 项目目录结构:一个标准的 Maven 工程
拿到源码第一步,先看目录结构。它是个标准的 Maven 工程,源码包按功能分包:
file-renamer/ ├── pom.xml ├── README.md └── src/ ├── main/ │ ├── java/ │ │ └── com/renamer/ │ │ ├── App.java # 入口类,启动 Swing 界面 │ │ ├── ui/ │ │ │ ├── MainFrame.java # 主窗口 │ │ │ ├── FileTableModel.java # 文件列表的表格模型 │ │ │ └── RulePanel.java # 规则配置面板 │ │ ├── rule/ │ │ │ ├── RenameRule.java # 规则接口 │ │ │ ├── RegexRule.java # 正则替换规则 │ │ │ ├── SequentialRule.java # 序号填充规则 │ │ │ └── CaseRule.java # 大小写转换规则 │ │ └── file/ │ │ ├── FileScanner.java # 目录扫描 │ │ ├── FileRenamer.java # 执行重命名 │ │ └── RenameHistory.java # 操作历史(支持撤销) │ └── resources/ └── test/ └── java/ └── com/renamer/ └── rule/ ├── RegexRuleTest.java └── SequentialRuleTest.java包名是com.renamer,不是什么大工程,但每个类的职责从名字上就能看出来。注意RenameHistory这个类,它是回滚功能的关键,后续我会重点讲。另外,测试目录里只覆盖了规则层,覆盖范围不算全,但规则解析作为最容易出错的部分被优先测试了,这个抓重点的思路值得学习。
3. 核心模块拆解:重命名的完整执行链路与关键代码
3.1 文件扫描:把无序文件变成表格里的一行行数据
重命名的第一步不是改,而是“看清楚要改什么”。FileScanner做的事就是把用户选择的目录下的文件递归扫描出来,过滤掉目录本身,同时按照文件名排序——这里特意用Collator来处理中文排序,否则“张三”和“张四”这种名字顺序会乱。
public List<FileItem> scan(File dir) { List<FileItem> result = new ArrayList<>(); File[] files = dir.listFiles(); if (files == null) { return result; } // 按文件名排序,避免 Windows 下返回顺序不一致 Arrays.sort(files, Comparator.comparing(File::getName, Collator.getInstance(Locale.CHINA))); for (File f : files) { if (f.isFile()) { result.add(new FileItem(f)); } } return result; }这里返回的不是File而是FileItem,这个内部类持有文件对象、原始文件名、新文件名和预览状态四个字段。FileItem是整个工具的数据载体,表格模型、预览逻辑、执行引擎都操作这个对象。之所以不直接用File,是因为重命名前后的名字对比需要在同一个对象上进行,你还得随时知道哪些行是“改过”的,哪些行是“跳过”的。
3.2 规则接口:让每种重命名策略都成为可插拔的插件
RenameRule是整个规则层的核心,它的定义简洁得近乎朴素:
public interface RenameRule { // 输入当前文件名,返回新文件名;返回 null 表示不应用此规则 String rename(String originName); }单方法接口,输入输出都在名字这个字符串上操作,不关心文件路径、不关心文件大小,这保证了规则的纯粹性。项目里默认实现了三类规则:RegexRule负责正则替换,比如把[192.168.1.1]report.pdf里的 IP 前缀去掉;SequentialRule负责追加序号,比如把一堆照片改成photo_001.jpg;CaseRule负责大小写转换,一键让所有文件名变成大写、小写或首字母大写。
每个规则都带一组配置参数,这些参数通过构造方法传入:
public class RegexRule implements RenameRule { private String pattern; // 正则表达式 private String replacement; // 替换后的目标串 private boolean useRegex; // 是否按正则匹配(false 时按普通字符串) public RegexRule(String pattern, String replacement, boolean useRegex) { this.pattern = pattern; this.replacement = replacement; this.useRegex = useRegex; } @Override public String rename(String originName) { if (useRegex) { // 用正则,注意允许替换为空字符串 return originName.replaceAll(pattern, replacement); } // 普通字符串替换,只替换第一个匹配 return originName.replace(pattern, replacement); } }注意到没有:useRegex这个参数区分了正则和字符串两种模式。因为正则没法处理*、?这些文件名里常见的通配符(它们在正则里都有特殊含义),普通用户很容易踩坑,加一个开关可以让不会正则的用户也能安全替换。这是源码里很贴心的细节,实践中有太多人把report(1).pdf里的括号直接填进正则然后发现匹配不上。
3.3 预览逻辑:先算后改,拒绝黑匣子
批量重命名最大的风险在于“一执行就全变”,如果规则写错了,几百个文件瞬间面目全非。这个项目把预览做成了强制环节:点“执行”之前,必须先点“预览”按钮,表格里会新增一列展示每个文件的新名字,并且新名字与旧名字完全相同的行会自动标记为“跳过”状态。
public void preview() { RenameRule rule = rulePanel.getCurrentRule(); for (FileItem item : fileTableModel.getItems()) { if (item.isSkip()) { // 被勾选跳过的行不参与预览 continue; } String newName = rule.rename(item.getOriginName()); if (newName == null || newName.isEmpty()) { // 规则返回空值,视为不匹配,保留原名 item.setNewName(item.getOriginName()); item.setStatus(Status.UNCHANGED); } else { item.setNewName(newName); // 名字没有变化,说明规则对这个文件不生效 item.setStatus(item.getOriginName().equals(newName) ? Status.UNCHANGED : Status.CHANGED); } } fileTableModel.fireTableDataChanged(); }预览并不真正改文件名,只是把FileItem里的newName字段填上,然后刷新表格。这里的Status枚举有三态:UNCHANGED表示规则没作用上,CHANGED表示将要被修改,ERROR表示新文件名非法(比如包含了 Windows 不允许的\ / : * ? " < > |字符)。ERROR状态的行在界面上标红,预览时发现问题还能在规则面板里直接改参数再预览一次,这个“试错循环”避免了很多不必要的灾难。
3.4 执行引擎:改名的同时要能“后悔”
执行环节的代码不算长,但它把文件重命名中容易忽略的点都处理掉了——目标路径已存在、文件被占用、重命名失败后的回滚。核心逻辑在FileRenamer里:
public RenameResult execute(List<FileItem> items) { RenameHistory history = new RenameHistory(); int successCount = 0; for (FileItem item : items) { if (item.isSkip() || item.getStatus() == Status.UNCHANGED) { continue; } File src = item.getFile(); File dest = new File(src.getParentFile(), item.getNewName()); // 检查目标是否存在,避免覆盖同名文件 if (dest.exists()) { item.setStatus(Status.ERROR); item.setErrorMsg("目标文件已存在"); continue; } // 记录修改前的状态,用于撤销 history.push(item); if (src.renameTo(dest)) { item.setFile(dest); successCount++; } else { item.setStatus(Status.ERROR); item.setErrorMsg("重命名失败,可能文件被占用"); } } return new RenameResult(successCount, history); }RenameHistory是这里最关键的辅助类。它内部维护一个栈,每次成功的重命名都把“原始文件”和“目标文件”这对映射压入栈中。撤销时从栈顶弹出,执行反向的renameTo:
public void undo() { while (!stack.isEmpty()) { UndoItem item = stack.pop(); File src = item.dest; // 当前位置 File dest = item.origin; // 原始位置 src.renameTo(dest); } }注意undo()是一次性撤销整个批次的全部操作,而不是只撤销最后一步。这样设计有个明显的好处:如果你在预览时发现规则错了,执行后又想后悔,可以一键全部回滚到最初状态,不用手动去挑“哪几个文件是被改过的”。做一个批量工具,提供“全量后悔药”比“逐步后悔药”更有价值,因为批量操作通常意味着你要回退的是一整套修改。
3.5 文件占用与跨平台的“隐藏坑”
重命名失败的场景有很多:文件正在被 Excel 打开、文件被杀毒软件扫描锁定、文件名末尾带了一个空格导致 Windows 拒绝处理。项目里对失败的处理策略是“标记错误,继续下一个”,而不是中断整个批次——这个选择很实用,因为批量场景下失败一两个不应当让整个任务停止。
代码里还处理了一个容易被忽视的场景:renameTo跨目录移动文件时行为不一致。这个工具里重命名前后的文件都在同一个目录下,所以renameTo永远是“同分区内的改名”,不涉及复制数据。如果哪天你要扩展成“移动文件到别的目录”,就不能再用renameTo了,得改用Files.move并带上StandardCopyOption。这是 Java 文件操作里的经典判别点,写代码时多留个心眼。
4. 运行与打包:从源码到可执行 jar 的完整步骤
4.1 环境准备与常见翻车点
要跑起这个项目,先确认本机环境:JDK 8 及以上(8 就行,项目没用任何新语法特性)、Maven 3.6+(打包时需要联网拉依赖,项目本身没有第三方依赖,所以下载量很小)、一个正常工作的终端。如果之前没装过 JDK,最常见的翻车点是java -version显示的是 JRE 而不是 JDK——Maven 强制需要完整的 JDK,光有 JRE 会报错。
验证 JDK 安装:
java -version mvn -version看到Maven home和Java version都正常输出了,再进下一步。如果你是某高校的开发者,实验室机器上经常会同时装多个 JDK 版本,建议先在~/.bashrc或~/.zshrc(Windows 在“系统属性→环境变量”)里固定好JAVA_HOME,不然 Maven 可能选中一个不存在的版本导致编译失败。
4.2 用 Maven 打包成可双击的 jar
项目自带pom.xml,打包命令很简单。进入项目根目录后执行:
mvn clean package第一次执行会下载 Maven 的插件,耐心等一会儿。构建成功后,target/目录下会出现两个文件:file-renamer-1.0.jar和file-renamer-1.0-jar-with-dependencies.jar。后者把依赖打进了 jar 里,体积稍大但可以直接运行。注意pom.xml里配置了maven-shade-plugin,它会自动生成MANIFEST.MF中的Main-Class指向com.renamer.App,这一步如果没配好,打包出来的 jar 会提示“没有主清单属性”,这是新手最常见的一个报错。
执行入口也支持命令行直接启动:
java -jar target/file-renamer-1.0-jar-with-dependencies.jar双击运行也可以,但 Windows 控制台的编码问题值得提前说一句:如果你的文件名里有中文,建议在启动时强制指定 UTF-8 编码:
java -Dfile.encoding=UTF-8 -jar target/file-renamer-1.0-jar-with-dependencies.jar不指定的话,在中文 Windows 系统上renameTo内部走过文件系统的时候倒是没问题,但界面里的中文文件名会在 Linux 或 macOS 上出现乱码。这是跨平台开发的血泪经验,等到用户的系统里看到????.pdf再排查心态容易崩,不如启动时就留一手。
4.3 配置规则:从界面操作到修改默认值
界面上的规则参数都通过RulePanel输入,每次打开都要重新填一遍确实麻烦。项目里提供了一个简单的默认配置文件default.properties,放在src/main/resources/下,里面预置了三条常用规则示例:
# 默认规则:去除文件名中的 [广告] 前缀 default.regex.pattern=\\[.*?\\] default.regex.replacement= # 默认序号:从 1 开始,补零到 3 位 default.sequential.prefix=photo_ default.sequential.digits=3 default.sequential.start=1 # 默认大小写:全部转为小写 default.case.mode=LOWERRulePanel启动时会读取这个 properties 文件,把预置的规则填进输入框。开发者拿到源码后想改默认行为,直接改这里就行,不用动代码。比如你希望序号从 100 开始,把default.sequential.start=100保存、重新打包即可。文件里的中文注释编码也保持 UTF-8,读取时用Properties默认的 ISO-8859-1 会乱码,项目里提供了一个Utf8ResourceBundle类来读取,这个小工具类也可以直接复制到其他项目复用。
4.4 常见启动失败排查
遇到启动打不开或者闪退,不要慌,先看终端输出。这里总结三个高频场景:
场景一:提示UnsupportedClassVersionError。这是你用高版本 JDK 编译的字节码,跑在低版本 JRE 上。解决方法是检查pom.xml里的maven.compiler.source和maven.compiler.target,确认是否低于当前 JDK 版本,或者升级本机 JDK。
场景二:界面打开了,但扫不到任何文件。检查FileScanner里的过滤条件,它默认只接收文件不接收目录。你可能选了一个全是子文件夹的目录,里面没有文件,自然列表是空的。这不是 bug,是过滤逻辑的设计意图。
场景三:Windows 下预览正常,执行时提示失败。大概率是文件被 Office 或浏览器占用。先关闭相关程序,或者把文件复制一份出来再执行批量操作。这个属于运行环境问题,代码里已经做了失败标记,不会造成误操作。
5. 避坑指南:批量重命名常见的 5 个翻车现场
5.1 文件名非法字符:预览显示正常,执行时却报错
现象:预览里新文件名看起来没问题,但点击“执行”后这一行直接标红,报“重命名失败”。
原因:Windows 文件名不允许出现\ / : * ? " < > |这些字符。但预览和执行的校验时机不同——预览只比对新旧名字是否相同,没做合法字符校验;执行时dest.exists()检查通过了,renameTo才会因为非法路径抛异常。
解决:在FileRenamer.execute里增加一段前置校验,把非法字符检测放进去。代码实现很简单:
private static final String ILLEGAL_CHARS = "\\\\/:*?\"<>|"; public boolean isIllegalName(String name) { for (char c : name.toCharArray()) { if (ILLEGAL_CHARS.indexOf(c) >= 0) { return true; } } return false; }我把这个校验放在了预览阶段,FileItem的状态也会变为ERROR,并提示具体哪个字符不合法。这样用户点执行前就能发现问题,不用等到红字出现再改。
5.2 中文文件名乱码:界面正常,打包后却变问号
现象:本地 IDEA 里运行一切正常,用java -jar启动后,界面上的中文文件名全变成????.pdf。
原因:控制台启动时 JVM 默认按系统字符集解码,Windows 中文环境默认是 GBK,而源码和编译环境是 UTF-8。IDEA 里运行时会自动把-Dfile.encoding=UTF-8加进去,所以发现不了问题。
解决:两种修法。一是启动命令带参数:java -Dfile.encoding=UTF-8 -jar xxx.jar,治标;二是在App.main入口里直接设置系统属性:
public static void main(String[] args) { // 在创建任何 Swing 组件之前设置 System.setProperty("file.encoding", "UTF-8"); // 同时设置输入输出流 System.setProperty("sun.jnu.encoding", "UTF-8"); new MainFrame().setVisible(true); }这个sun.jnu.encoding属性卡了很多人一下午,它控制的是 JVM 与文件系统交互时的编码,默认跟随系统。图标类的资源如果还乱码,检查代码文件本身是否已保存为 UTF-8,IDE 右下角能看到。
5.3 文件被占用:Excel 开着文件,重命名静默失败
现象:列表里多行状态变成了ERROR,错误是“重命名失败,可能文件被占用”。
原因:File的renameTo在 Windows 上遇到被其他进程打开的文件会静默返回false,不抛异常。Excel、WPS、浏览器下载任务都可能持有句柄。
解决:代码里已经做了false判断并标记错误。但更好的做法是执行前先尝试拿一个FileChannel判断能否独占:
public boolean isFileLocked(File file) { try (FileChannel channel = FileChannel.open(file.toPath(), StandardOpenOption.WRITE)) { return false; } catch (IOException e) { return true; } }这个方法的原理是:能被打开写通道说明没被独占锁占用,否则抛OverlappingFileLockException或AccessDeniedException。把这个检查放到execute循环里,能过滤掉大部分占用场景,减少失败行数。
5.4 正则写错导致匹配失效:以为匹配上了,其实一直没变
现象:用户填了.*?或\d+这类正则,结果文件名字毫无变化,状态一直是UNCHANGED。
原因:大多数用户把正则和通配符混为一谈。比如想去掉文件名中的所有数字,他们写*,在正则里*是“重复前一个字符 0 次或多次”,前面没有字符时就匹配空,自然替换无效果。
解决:在RegexRule里捕获正则编译异常或空匹配,并在界面上给出提示。我习惯在rename方法里加一个日志输出,把不匹配的原始名称打印到终端,方便排查。同时把useRegex的默认值设为false(纯字符串替换),用户显式勾选“启用正则”才走正则逻辑,降低误用概率。
5.5 撤销失效:改了文件名以后,原文件找不回来了
现象:点了“撤销”,结果文件没有恢复原样,或者恢复了一部分。
原因:RenameHistory只在内存里保存了FileItem的引用,如果程序中途崩溃、被强制关闭,历史记录直接丢失。而且如果用户在执行后又手动改动了一些文件名,撤销时会用错的映射去反向改名。
解决:给RenameHistory加上一个持久化能力,把撤销记录写入一个临时文件。代码思路:
public void saveToFile(String path) { try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path))) { for (UndoItem item : stack) { oos.writeObject(item.origin.getName()); oos.writeObject(item.dest.getName()); } } catch (IOException e) { e.printStackTrace(); } }程序崩溃后重跑,如果有残留的撤销文件就提示用户“检测到上次未完成的操作,是否撤销”。这个功能在原项目里没做,但属于批量操作类工具非常值得补齐的一环。
6. 二次开发实战:给工具加一个“按创建日期重命名”的规则
6.1 需求场景与接口设计
原始工具支持正则、序号、大小写三类规则,但最常见的“按时间归档”没有覆盖。比如你想把照片按拍摄日期重命名成2025-06-01_IMG_123.jpg,当前版本做不了。这个需求是产品经理最常提的一类。顺着接口思路扩展一次,能看出这套架构的兼容性到底如何。
新规则的入参要比之前多一个“日期类型”选项:创建时间、修改时间、拍摄时间(从 EXIF 里读,但 EXIF 解析需要第三方依赖,这里先不做)。创建时间和修改时间从File对象上直接能拿。我把新类命名为DateRule:
6.2 实现 DateRule
public class DateRule implements RenameRule { private String pattern; // 日期格式,例如 yyyy-MM-dd private boolean useCreateTime; // true 用创建时间,false 用最后修改时间 private String prefix; // 文件名前缀,例如 "photo_" private String suffix; // 文件名后缀,例如 ".jpg" public DateRule(String pattern, boolean useCreateTime, String prefix, String suffix) { this.pattern = pattern; this.useCreateTime = useCreateTime; this.prefix = prefix; this.suffix = suffix; } @Override public String rename(String originName) { // 取文件路径需要通过 FileItem,这里做一层适配 return null; } }这里暴露了一个问题:RenameRule.rename只有文件名这一入参,没有 File 对象,拿不到创建时间。这是原接口设计上的局限。我知道要扩展接口,但又不想破坏已有的三个实现,可以采用“默认方法 + 新接口”的方式:
public interface RenameRule { String rename(String originName); // 默认实现,返回空适配模式 default String renameWithFile(FileItem item) { return rename(item.getOriginName()); } }新加的renameWithFile方法是个默认方法,老实现不用改,DateRule重写它去拿文件时间:
@Override public String renameWithFile(FileItem item) { File file = item.getFile(); long time = useCreateTime ? Files.readAttributes(file.toPath(), BasicFileAttributes.class).creationTime().toMillis() : file.lastModified(); SimpleDateFormat sdf = new SimpleDateFormat(pattern); return prefix + sdf.format(new Date(time)) + "_" + item.getOriginName().replaceAll("\\.[^.]+$", "") + suffix; }这样扩展的核心点在于:DefaultFileRenamer执行时判断rule instanceof DateRule,是则调用renameWithFile,否则调用rename。
6.3 界面注册与验证
RulePanel里增加一个下拉框“日期类型”,选中后显示日期格式输入框。这部分的代码不复杂,关键是提交时把选项打包成DateRule实例,交给预览逻辑。
验证方式分三层。第一层:单元测试,模仿已有的RegexRuleTest:
@Test public void testDateRuleFormat() { File temp = File.createTempFile("test", ".txt"); DateRule rule = new DateRule("yyyy-MM-dd", true, "photo_", ".bak"); FileItem item = new FileItem(temp); String result = rule.renameWithFile(item); assertTrue(result.matches("photo_\\d{4}-\\d{2}-\\d{2}_test\\.bak")); }第二层:界面操作验证——选一个含多个文件的目录,加日期规则,预览后确认新名字格式正确,再执行并撤销一次,确认历史回滚不受影响。第三层:边界测试——文件系统不支持读取创建时间时(如某些 Linux 挂载卷),代码会抛出IOException,需要在renameWithFile里捕获并让该行状态变为ERROR,而不是中断整个循环。
做完这个扩展再回头看,初始设计的接口确实够用但不够完美。rename的单参数约束让文件元数据拿不到,只能通过默认方法补。如果当初设计时就意识到“重命名不光看名字,还要看文件本身”,把FileItem作为入参直接传进去,后续扩展会更平滑。这也是拆解这类小项目最有价值的收获:看一个架构的坑,比自己从零造一个轮子要快得多。
从那以后,我每次设计接口都会先问一句:“这个方法的入参,三年后还会不会够?”批量重命名这类工具看着简单,真正上手就发现文件占用、字符校验、历史记录、跨平台编码,每个环节都能让你翻车。这个项目走通了一整条链路,源码拿过来跑一遍再动手改,比对着文档空想你自己的实现要省力得多。希望帮到你。
本文还有配套的精品资源,点击获取