下載的視頻、音樂、文檔常攜帶網站水印、廣告前綴、亂碼編號等「垃圾字符」,如 [電影天堂www.dytt8.net]復仇者聯盟.mp4、001_課程介紹.pdf。作為強迫症晚期患者,手動改名不可取,Java + 正則表達式批量重命名才是正解。
File.renameTo() 與 Pattern/MatcherFile.list() / listFiles():獲取目錄下文件名/文件對象Pattern.compile(regex):編譯正則,效能優於字符串 matches()Matcher.find() / group():查找並提取匹配片段File.renameTo(new File(parent, newName)):原子重命名,**必須使用絕對路徑**public class BatchRenamer {
private final File directory;
private final Pattern pattern;
private final String replacement;
public BatchRenamer(String dirPath, String regex, String replacement) {
this.directory = new File(dirPath);
if (!directory.isDirectory()) throw new IllegalArgumentException("非目錄:" + dirPath);
this.pattern = Pattern.compile(regex);
this.replacement = replacement;
}
public int execute() {
File[] files = directory.listFiles();
if (files == null) return 0;
int count = 0;
for (File file : files) {
if (!file.isFile()) continue;
String oldName = file.getName();
Matcher matcher = pattern.matcher(oldName);
if (matcher.find()) {
String matched = matcher.group(); // 完整匹配內容
String newName = oldName.replace(matched, replacement);
File target = new File(directory, newName);
if (file.renameTo(target)) {
System.out.printf("✅ %s → %s%n", oldName, newName);
count++;
} else {
System.err.printf("❌ 重命名失敗:%s%n", oldName);
}
}
}
return count;
}
// 靜態工廠方法:常用場景一鍵調用
public static int removePrefix(String dir, String prefixRegex) {
return new BatchRenamer(dir, prefixRegex, "").execute();
}
public static int replacePattern(String dir, String regex, String replacement) {
return new BatchRenamer(dir, regex, replacement).execute();
}
public static int prependMatchedNumber(String dir, String numberRegex) {
// 將文件名開頭的數字提取並作為前綴:"001_課程.pdf" → "001 001_課程.pdf"
return new BatchRenamer(dir, numberRegex, "") {
@Override
public int execute() {
File[] files = directory.listFiles();
if (files == null) return 0;
int count = 0;
for (File file : files) {
if (!file.isFile()) continue;
String oldName = file.getName();
Matcher m = pattern.matcher(oldName);
if (m.find()) {
String num = m.group();
String newName = num + " " + oldName;
File target = new File(directory, newName);
if (file.renameTo(target)) {
System.out.printf("✅ %s → %s%n", oldName, newName);
count++;
}
}
}
return count;
}
}.execute();
}
}
public class RenameDemo {
public static void main(String[] args) {
// 1. 刪除固定前綴:[電影天堂www.dytt8.net]
BatchRenamer.removePrefix("G:/Movies", "\\[電影天堂www\\.dytt8\\.net\\]");
// 2. 刪除年份+來源前綴:2023.優酷網- / 2022.搜狐視頻-
BatchRenamer.removePrefix("G:/TV", "\\d{4}\\.(優酷網|搜狐視頻)-");
// 3. 將開頭數字提取為前綴(便於排序):001_課程.pdf → 001 001_課程.pdf
BatchRenamer.prependMatchedNumber("G:/Courses", "^\\d+");
// 4. 通用替換:將所有 "_H265_" 替換為 " [HEVC] "
BatchRenamer.replacePattern("G:/Videos", "_H265_", " [HEVC] ");
}
}
| 場景 | 技巧 |
|---|---|
| 大量文件(>1萬) | 使用 Files.walkFileTree 遞歸遍歷,配合 ForkJoinPool 並行處理 |
| 跨文件系統移動 | renameTo() 跨分區會失敗,改用 Files.move(src, dst, StandardCopyOption.ATOMIC_MOVE) |
| 文件名編碼亂碼 | JDK 7+ 默認 UTF-8,舊系統可用 new String(oldName.getBytes("ISO-8859-1"), "GBK") 修正 |
| 撤銷操作 | 執行前記錄 Map<旧名, 新名> 到 JSON/CSV,提供 rollback() 方法 |
| 隱藏/系統文件 | file.isHidden() 過濾,或使用 FileFilter 自定義 |
^\d+ # 行首數字(如 001_)
\d{4}\.\w+- # 年份.來源- (如 2023.優酷網-)
\[[^\]]+\] # 方括號內容(如 [電影天堂...])
_\w+_ # 下劃線包裹詞(如 _H265_)
\.(mp4|mkv|avi)$ # 視頻後綴(用於過濾特定類型)
Java 配合正則表達式實現文件批量重命名,核心在於 Pattern 編譯複用、Matcher 精準提取、renameTo 絕對路徑 三要素。封裝通用工具類後,只需一行代碼即可應對「去水印、統一格式、提取編號」等多樣化需求。建議在項目中集成「預覽模式」(dryRun=true 僅打印不執行)與「操作日誌持久化」,讓批量重命名既高效又可追溯、可回滾。