下載影片/音樂常遇到檔名包含冗長廣告前後綴 (如「【某網站】電影名(廣告尾巴).mp4」),手動改名極其繁瑣。本工具支援多規則鏈式替換,一次處理整個資料夾。
/** 重命名規則鏈:支援鏈式呼叫 addRule() */
public class RenameRuleChain {
private final Map rules = new LinkedHashMap<>(); // 保持規則順序
public RenameRuleChain addRule(String from, String to) {
rules.put(from, to);
return this; // 鏈式呼叫
}
public Map getRules() {
return Collections.unmodifiableMap(rules);
}
}
public class BatchRenamer {
/** 批量重命名主入口 */
public static void rename(String folderPath, RenameRuleChain ruleChain) {
File folder = new File(folderPath);
// 1. 參數驗證
if (!folder.exists()) {
throw new IllegalArgumentException("資料夾不存在: " + folderPath);
}
if (!folder.isDirectory()) {
throw new IllegalArgumentException("路徑非資料夾: " + folderPath);
}
// 2. 取得檔案列表
File[] files = folder.listFiles(File::isFile); // 僅處理檔案,忽略子目錄
if (files == null || files.length == 0) {
System.out.println("資料夾無檔案: " + folderPath);
return;
}
// 3. 套用規則逐一重命名
int success = 0, failed = 0;
for (File file : files) {
String oldName = file.getName();
String newName = applyRules(oldName, ruleChain.getRules());
if (!oldName.equals(newName)) {
File target = new File(folder, newName);
if (target.exists()) {
System.err.printf("衝突跳過: %s → %s (目標已存在)%n", oldName, newName);
failed++;
continue;
}
if (file.renameTo(target)) {
System.out.printf("重命名: %s → %s%n", oldName, newName);
success++;
} else {
System.err.printf("重命名失敗: %s → %s%n", oldName, newName);
failed++;
}
}
}
System.out.printf("完成! 成功: %d, 失敗: %d, 無變更: %d%n",
success, failed, files.length - success - failed);
}
/** 依序套用所有替換規則 */
private static String applyRules(String fileName, Map rules) {
String result = fileName;
for (Map.Entry rule : rules.entrySet()) {
result = result.replace(rule.getKey(), rule.getValue());
}
return result;
}
}
public class Main {
public static void main(String[] args) {
// 1. 建立規則鏈
RenameRuleChain chain = new RenameRuleChain()
.addRule("【我是一個好長好長的前綴哦】~~~~~", "") // 移除前綴
.addRule("(我是萌萌的小尾巴)", "") // 移除後綴
.addRule(" ", "_") // 空格替換底線
.addRule("(", "[").addRule(")", "]"); // 括號統一
// 2. 執行重命名
String targetFolder = "F:\\測試資料夾"; // 雙反斜線或正斜線均可
BatchRenamer.rename(targetFolder, chain);
}
}


// 重命名前 【我是一個好長好長的前綴哦】~~~~~ 小說001(我是萌萌的小尾巴).txt 【我是一個好長好長的前綴哦】~~~~~ 小說002(我是萌萌的小尾巴).txt 【我是一個好長好長的前綴哦】~~~~~ 小說003(我是萌萌的小尾巴).txt // 重命名後 小說001.txt 小說002.txt 小說003.txt
public class RegexRuleChain {
private final List> rules = new ArrayList<>();
public RegexRuleChain addRegex(String regex, String replacement) {
rules.add(new Pair<>(Pattern.compile(regex), replacement));
return this;
}
public String apply(String input) {
String result = input;
for (Pair rule : rules) {
result = rule.getKey().matcher(result).replaceAll(rule.getValue());
}
return result;
}
}
// 使用: .addRegex("\\[.*?\\]", "").addRegex("\\(.*?\\)", "") // 移除所有 [] 和 () 內容
public void previewRename(String folderPath, RenameRuleChain chain) {
File[] files = new File(folderPath).listFiles(File::isFile);
System.out.println("=== 預覽模式 (不會實際重命名) ===");
for (File f : files) {
String newName = applyRules(f.getName(), chain.getRules());
if (!f.getName().equals(newName)) {
System.out.printf("%s → %s%n", f.getName(), newName);
}
}
}
public class UndoableRenamer {
private final List history = new ArrayList<>();
public void renameWithUndo(String folder, RenameRuleChain chain) {
File dir = new File(folder);
File[] files = dir.listFiles(File::isFile);
for (File f : files) {
String oldName = f.getName();
String newName = applyRules(oldName, chain.getRules());
if (!oldName.equals(newName)) {
File target = new File(dir, newName);
if (f.renameTo(target)) {
history.add(new RenameRecord(target, new File(dir, oldName)));
}
}
}
}
public void undo() {
Collections.reverse(history);
for (RenameRecord r : history) {
r.getCurrent().renameTo(r.getOriginal());
}
history.clear();
}
static class RenameRecord {
private final File current, original;
RenameRecord(File current, File original) { this.current = current; this.original = original; }
File getCurrent() { return current; }
File getOriginal() { return original; }
}
}
@Test
public void testRuleChain() {
RenameRuleChain chain = new RenameRuleChain()
.addRule("prefix_", "")
.addRule("_suffix", "")
.addRule(" ", "-");
assertEquals("file-name.txt", chain.applyRules("prefix_file name.txt_suffix"));
assertEquals("no-change.txt", chain.applyRules("no-change.txt"));
}
@Test
public void testBatchRename() throws IOException {
Path tempDir = Files.createTempDirectory("rename-test");
Files.createFile(tempDir.resolve("old_001.txt"));
Files.createFile(tempDir.resolve("old_002.txt"));
BatchRenamer.rename(tempDir.toString(),
new RenameRuleChain().addRule("old_", "new_"));
assertTrue(Files.exists(tempDir.resolve("new_001.txt")));
assertTrue(Files.exists(tempDir.resolve("new_002.txt")));
}