Introduction
A comprehensive batch file renamer utility that provides multiple renaming strategies, preview capabilities, and robust error handling. This tool can handle various file renaming scenarios including pattern-based renaming, sequential numbering, case conversion, and more.
Core Implementation
Main Batch File Renamer Class
import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.regex.*;
import java.util.stream.Collectors;
public class BatchFileRenamer {
private final List<File> files;
private final List<RenameOperation> operations;
private boolean previewMode;
public BatchFileRenamer() {
this.files = new ArrayList<>();
this.operations = new ArrayList<>();
this.previewMode = true; // Default to preview mode for safety
}
public void addFile(File file) {
if (file.exists() && file.isFile()) {
files.add(file);
} else {
throw new IllegalArgumentException("File does not exist or is not a regular file: " + file.getPath());
}
}
public void addFiles(List<File> files) {
for (File file : files) {
addFile(file);
}
}
public void addFilesFromDirectory(File directory, boolean recursive) {
if (!directory.exists() || !directory.isDirectory()) {
throw new IllegalArgumentException("Directory does not exist: " + directory.getPath());
}
try {
List<File> foundFiles = findFiles(directory, recursive);
files.addAll(foundFiles);
} catch (IOException e) {
throw new RuntimeException("Error reading directory: " + e.getMessage(), e);
}
}
private List<File> findFiles(File directory, boolean recursive) throws IOException {
if (!recursive) {
return Arrays.stream(Objects.requireNonNull(directory.listFiles()))
.filter(File::isFile)
.collect(Collectors.toList());
}
List<File> result = new ArrayList<>();
Files.walk(directory.toPath())
.filter(Files::isRegularFile)
.forEach(path -> result.add(path.toFile()));
return result;
}
public void setPreviewMode(boolean previewMode) {
this.previewMode = previewMode;
}
// Renaming operations
public void addReplaceOperation(String search, String replacement) {
operations.add(new ReplaceOperation(search, replacement));
}
public void addRegexOperation(String regex, String replacement) {
operations.add(new RegexOperation(regex, replacement));
}
public void addPrefixOperation(String prefix) {
operations.add(new PrefixOperation(prefix));
}
public void addSuffixOperation(String suffix) {
operations.add(new SuffixOperation(suffix));
}
public void addCaseOperation(CaseType caseType) {
operations.add(new CaseOperation(caseType));
}
public void addSequentialNumbering(String prefix, String suffix, int startNumber, int digits) {
operations.add(new SequentialNumberingOperation(prefix, suffix, startNumber, digits));
}
public void addExtensionChange(String newExtension) {
operations.add(new ExtensionChangeOperation(newExtension));
}
public void addCustomOperation(RenameOperation operation) {
operations.add(operation);
}
public List<RenameResult> previewRename() {
return performRename(true);
}
public List<RenameResult> executeRename() {
return performRename(false);
}
private List<RenameResult> performRename(boolean preview) {
List<RenameResult> results = new ArrayList<>();
Map<String, Integer> nameCounts = new HashMap<>();
for (File originalFile : files) {
try {
String originalName = originalFile.getName();
String newName = applyOperations(originalName);
// Handle name conflicts
newName = resolveNameConflict(originalFile.getParent(), newName, nameCounts);
File newFile = new File(originalFile.getParent(), newName);
RenameResult result = new RenameResult(originalFile, newFile, RenameStatus.PENDING);
if (!preview) {
boolean success = originalFile.renameTo(newFile);
result = new RenameResult(originalFile, newFile,
success ? RenameStatus.SUCCESS : RenameStatus.FAILED);
if (success) {
// Update the file reference for subsequent operations
files.set(files.indexOf(originalFile), newFile);
}
}
results.add(result);
} catch (Exception e) {
results.add(new RenameResult(originalFile, null, RenameStatus.ERROR, e.getMessage()));
}
}
return results;
}
private String applyOperations(String filename) {
String result = filename;
for (RenameOperation operation : operations) {
result = operation.apply(result);
}
return result;
}
private String resolveNameConflict(String directory, String filename, Map<String, Integer> nameCounts) {
String baseName = filename;
String extension = "";
int dotIndex = filename.lastIndexOf('.');
if (dotIndex > 0) {
baseName = filename.substring(0, dotIndex);
extension = filename.substring(dotIndex);
}
String key = directory + File.separator + baseName + extension;
int count = nameCounts.getOrDefault(key, 0);
nameCounts.put(key, count + 1);
if (count == 0) {
return filename;
}
return baseName + " (" + count + ")" + extension;
}
public void clearOperations() {
operations.clear();
}
public void clearFiles() {
files.clear();
}
public int getFileCount() {
return files.size();
}
public int getOperationCount() {
return operations.size();
}
public List<File> getFiles() {
return new ArrayList<>(files);
}
// Result classes
public static class RenameResult {
private final File originalFile;
private final File newFile;
private final RenameStatus status;
private final String errorMessage;
public RenameResult(File originalFile, File newFile, RenameStatus status) {
this(originalFile, newFile, status, null);
}
public RenameResult(File originalFile, File newFile, RenameStatus status, String errorMessage) {
this.originalFile = originalFile;
this.newFile = newFile;
this.status = status;
this.errorMessage = errorMessage;
}
// Getters
public File getOriginalFile() { return originalFile; }
public File getNewFile() { return newFile; }
public RenameStatus getStatus() { return status; }
public String getErrorMessage() { return errorMessage; }
@Override
public String toString() {
return String.format("%s -> %s [%s]",
originalFile.getName(),
newFile != null ? newFile.getName() : "N/A",
status);
}
}
public enum RenameStatus {
PENDING, SUCCESS, FAILED, ERROR
}
public enum CaseType {
UPPERCASE, LOWERCASE, CAMELCASE, TITLE_CASE
}
}
Renaming Operations Interface and Implementations
Operation Interface and Base Classes
// Main operation interface
interface RenameOperation {
String apply(String filename);
String getDescription();
}
// Abstract base class for common functionality
abstract class AbstractRenameOperation implements RenameOperation {
protected final String name;
protected AbstractRenameOperation(String name) {
this.name = name;
}
@Override
public String getDescription() {
return name;
}
protected String getBaseName(String filename) {
int dotIndex = filename.lastIndexOf('.');
return dotIndex > 0 ? filename.substring(0, dotIndex) : filename;
}
protected String getExtension(String filename) {
int dotIndex = filename.lastIndexOf('.');
return dotIndex > 0 ? filename.substring(dotIndex) : "";
}
}
// Replace text operation
class ReplaceOperation extends AbstractRenameOperation {
private final String search;
private final String replacement;
public ReplaceOperation(String search, String replacement) {
super("Replace '" + search + "' with '" + replacement + "'");
this.search = search;
this.replacement = replacement;
}
@Override
public String apply(String filename) {
String baseName = getBaseName(filename);
String extension = getExtension(filename);
String newBaseName = baseName.replace(search, replacement);
return newBaseName + extension;
}
}
// Regex-based replacement operation
class RegexOperation extends AbstractRenameOperation {
private final Pattern pattern;
private final String replacement;
public RegexOperation(String regex, String replacement) {
super("Regex replace '" + regex + "' with '" + replacement + "'");
this.pattern = Pattern.compile(regex);
this.replacement = replacement;
}
@Override
public String apply(String filename) {
String baseName = getBaseName(filename);
String extension = getExtension(filename);
Matcher matcher = pattern.matcher(baseName);
String newBaseName = matcher.replaceAll(replacement);
return newBaseName + extension;
}
}
// Add prefix operation
class PrefixOperation extends AbstractRenameOperation {
private final String prefix;
public PrefixOperation(String prefix) {
super("Add prefix '" + prefix + "'");
this.prefix = prefix;
}
@Override
public String apply(String filename) {
String baseName = getBaseName(filename);
String extension = getExtension(filename);
return prefix + baseName + extension;
}
}
// Add suffix operation
class SuffixOperation extends AbstractRenameOperation {
private final String suffix;
public SuffixOperation(String suffix) {
super("Add suffix '" + suffix + "'");
this.suffix = suffix;
}
@Override
public String apply(String filename) {
String baseName = getBaseName(filename);
String extension = getExtension(filename);
return baseName + suffix + extension;
}
}
// Case conversion operation
class CaseOperation extends AbstractRenameOperation {
private final BatchFileRenamer.CaseType caseType;
public CaseOperation(BatchFileRenamer.CaseType caseType) {
super("Convert to " + caseType.toString().toLowerCase());
this.caseType = caseType;
}
@Override
public String apply(String filename) {
String baseName = getBaseName(filename);
String extension = getExtension(filename);
String newBaseName;
switch (caseType) {
case UPPERCASE:
newBaseName = baseName.toUpperCase();
break;
case LOWERCASE:
newBaseName = baseName.toLowerCase();
break;
case CAMELCASE:
newBaseName = toCamelCase(baseName);
break;
case TITLE_CASE:
newBaseName = toTitleCase(baseName);
break;
default:
newBaseName = baseName;
}
return newBaseName + extension;
}
private String toCamelCase(String text) {
if (text == null || text.isEmpty()) {
return text;
}
String[] words = text.split("[\\s_\\-]+");
StringBuilder result = new StringBuilder();
for (int i = 0; i < words.length; i++) {
String word = words[i];
if (!word.isEmpty()) {
if (i == 0) {
result.append(word.toLowerCase());
} else {
result.append(Character.toUpperCase(word.charAt(0)))
.append(word.substring(1).toLowerCase());
}
}
}
return result.toString();
}
private String toTitleCase(String text) {
if (text == null || text.isEmpty()) {
return text;
}
String[] words = text.split("[\\s_\\-]+");
StringBuilder result = new StringBuilder();
for (String word : words) {
if (!word.isEmpty()) {
if (result.length() > 0) {
result.append(" ");
}
result.append(Character.toUpperCase(word.charAt(0)))
.append(word.substring(1).toLowerCase());
}
}
return result.toString();
}
}
// Sequential numbering operation
class SequentialNumberingOperation extends AbstractRenameOperation {
private final String prefix;
private final String suffix;
private final int startNumber;
private final int digits;
private int currentNumber;
public SequentialNumberingOperation(String prefix, String suffix, int startNumber, int digits) {
super("Sequential numbering starting from " + startNumber);
this.prefix = prefix != null ? prefix : "";
this.suffix = suffix != null ? suffix : "";
this.startNumber = startNumber;
this.digits = Math.max(1, digits);
this.currentNumber = startNumber;
}
@Override
public String apply(String filename) {
String baseName = getBaseName(filename);
String extension = getExtension(filename);
String numberStr = String.format("%0" + digits + "d", currentNumber);
String newBaseName = prefix + baseName + suffix + " " + numberStr;
currentNumber++;
return newBaseName + extension;
}
public void reset() {
currentNumber = startNumber;
}
}
// Extension change operation
class ExtensionChangeOperation extends AbstractRenameOperation {
private final String newExtension;
public ExtensionChangeOperation(String newExtension) {
super("Change extension to '" + newExtension + "'");
this.newExtension = newExtension.startsWith(".") ? newExtension : "." + newExtension;
}
@Override
public String apply(String filename) {
String baseName = getBaseName(filename);
return baseName + newExtension;
}
}
// Remove characters operation
class RemoveCharactersOperation extends AbstractRenameOperation {
private final String charactersToRemove;
public RemoveCharactersOperation(String charactersToRemove) {
super("Remove characters: '" + charactersToRemove + "'");
this.charactersToRemove = charactersToRemove;
}
@Override
public String apply(String filename) {
String baseName = getBaseName(filename);
String extension = getExtension(filename);
String newBaseName = baseName;
for (char c : charactersToRemove.toCharArray()) {
newBaseName = newBaseName.replace(String.valueOf(c), "");
}
return newBaseName + extension;
}
}
// Truncate operation
class TruncateOperation extends AbstractRenameOperation {
private final int maxLength;
public TruncateOperation(int maxLength) {
super("Truncate to " + maxLength + " characters");
this.maxLength = maxLength;
}
@Override
public String apply(String filename) {
String baseName = getBaseName(filename);
String extension = getExtension(filename);
if (baseName.length() <= maxLength) {
return filename;
}
String newBaseName = baseName.substring(0, maxLength);
return newBaseName + extension;
}
}
Advanced File Filtering System
File Filter Implementation
import java.io.File;
import java.io.FileFilter;
import java.util.function.Predicate;
// Advanced file filter system
public class AdvancedFileFilter implements FileFilter {
private final List<Predicate<File>> predicates;
private boolean includeMode = true; // true = include, false = exclude
public AdvancedFileFilter() {
this.predicates = new ArrayList<>();
}
public static AdvancedFileFilter create() {
return new AdvancedFileFilter();
}
public AdvancedFileFilter include() {
this.includeMode = true;
return this;
}
public AdvancedFileFilter exclude() {
this.includeMode = false;
return this;
}
public AdvancedFileFilter byExtension(String... extensions) {
Predicate<File> extensionPredicate = file -> {
String filename = file.getName().toLowerCase();
for (String ext : extensions) {
String lowerExt = ext.toLowerCase();
if (!lowerExt.startsWith(".")) {
lowerExt = "." + lowerExt;
}
if (filename.endsWith(lowerExt)) {
return true;
}
}
return false;
};
predicates.add(extensionPredicate);
return this;
}
public AdvancedFileFilter byNamePattern(String pattern) {
Predicate<File> namePredicate = file -> {
String filename = file.getName();
return filename.matches(pattern);
};
predicates.add(namePredicate);
return this;
}
public AdvancedFileFilter byNameContains(String text) {
Predicate<File> containsPredicate = file ->
file.getName().toLowerCase().contains(text.toLowerCase());
predicates.add(containsPredicate);
return this;
}
public AdvancedFileFilter bySizeRange(long minSize, long maxSize) {
Predicate<File> sizePredicate = file -> {
long size = file.length();
return size >= minSize && size <= maxSize;
};
predicates.add(sizePredicate);
return this;
}
public AdvancedFileFilter byMinSize(long minSize) {
return bySizeRange(minSize, Long.MAX_VALUE);
}
public AdvancedFileFilter byMaxSize(long maxSize) {
return bySizeRange(0, maxSize);
}
public AdvancedFileFilter byLastModified(long from, long to) {
Predicate<File> timePredicate = file -> {
long lastModified = file.lastModified();
return lastModified >= from && lastModified <= to;
};
predicates.add(timePredicate);
return this;
}
public AdvancedFileFilter modifiedAfter(long timestamp) {
return byLastModified(timestamp, Long.MAX_VALUE);
}
public AdvancedFileFilter modifiedBefore(long timestamp) {
return byLastModified(0, timestamp);
}
public AdvancedFileFilter hiddenFiles(boolean includeHidden) {
Predicate<File> hiddenPredicate = file -> includeHidden == file.isHidden();
predicates.add(hiddenPredicate);
return this;
}
@Override
public boolean accept(File file) {
if (!file.isFile()) {
return false;
}
if (predicates.isEmpty()) {
return true;
}
boolean matchesAll = predicates.stream().allMatch(predicate -> predicate.test(file));
return includeMode ? matchesAll : !matchesAll;
}
public List<File> filterFiles(File[] files) {
return Arrays.stream(files)
.filter(this::accept)
.collect(Collectors.toList());
}
public List<File> filterFiles(List<File> files) {
return files.stream()
.filter(this::accept)
.collect(Collectors.toList());
}
}
GUI Application (Swing)
Main GUI Interface
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.util.List;
public class BatchFileRenamerGUI extends JFrame {
private final BatchFileRenamer renamer;
private DefaultTableModel tableModel;
private JTable filesTable;
private JTextArea previewArea;
private JLabel statusLabel;
public BatchFileRenamerGUI() {
this.renamer = new BatchFileRenamer();
initializeUI();
}
private void initializeUI() {
setTitle("Batch File Renamer");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(1000, 700);
setLocationRelativeTo(null);
createMenuBar();
createMainPanel();
createStatusBar();
setVisible(true);
}
private void createMenuBar() {
JMenuBar menuBar = new JMenuBar();
// File menu
JMenu fileMenu = new JMenu("File");
JMenuItem addFilesItem = new JMenuItem("Add Files...");
JMenuItem addFolderItem = new JMenuItem("Add Folder...");
JMenuItem clearFilesItem = new JMenuItem("Clear Files");
JMenuItem exitItem = new JMenuItem("Exit");
addFilesItem.addActionListener(e -> addFiles());
addFolderItem.addActionListener(e -> addFolder());
clearFilesItem.addActionListener(e -> clearFiles());
exitItem.addActionListener(e -> System.exit(0));
fileMenu.add(addFilesItem);
fileMenu.add(addFolderItem);
fileMenu.addSeparator();
fileMenu.add(clearFilesItem);
fileMenu.addSeparator();
fileMenu.add(exitItem);
// Operations menu
JMenu operationsMenu = new JMenu("Operations");
JMenuItem replaceItem = new JMenuItem("Replace Text...");
JMenuItem regexItem = new JMenuItem("Regex Replace...");
JMenuItem prefixItem = new JMenuItem("Add Prefix...");
JMenuItem suffixItem = new JMenuItem("Add Suffix...");
JMenuItem caseItem = new JMenuItem("Change Case...");
JMenuItem numberingItem = new JMenuItem("Sequential Numbering...");
JMenuItem extensionItem = new JMenuItem("Change Extension...");
JMenuItem clearOpsItem = new JMenuItem("Clear Operations");
replaceItem.addActionListener(e -> showReplaceDialog());
regexItem.addActionListener(e -> showRegexDialog());
prefixItem.addActionListener(e -> showPrefixDialog());
suffixItem.addActionListener(e -> showSuffixDialog());
caseItem.addActionListener(e -> showCaseDialog());
numberingItem.addActionListener(e -> showNumberingDialog());
extensionItem.addActionListener(e -> showExtensionDialog());
clearOpsItem.addActionListener(e -> clearOperations());
operationsMenu.add(replaceItem);
operationsMenu.add(regexItem);
operationsMenu.addSeparator();
operationsMenu.add(prefixItem);
operationsMenu.add(suffixItem);
operationsMenu.add(caseItem);
operationsMenu.addSeparator();
operationsMenu.add(numberingItem);
operationsMenu.add(extensionItem);
operationsMenu.addSeparator();
operationsMenu.add(clearOpsItem);
menuBar.add(fileMenu);
menuBar.add(operationsMenu);
setJMenuBar(menuBar);
}
private void createMainPanel() {
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
splitPane.setResizeWeight(0.6);
// Upper panel - Files table and operations
JPanel upperPanel = new JPanel(new BorderLayout());
// Files table
String[] columnNames = {"Original Name", "New Name", "Status", "Path"};
tableModel = new DefaultTableModel(columnNames, 0) {
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
filesTable = new JTable(tableModel);
JScrollPane tableScrollPane = new JScrollPane(filesTable);
// Operations panel
JPanel operationsPanel = new JPanel(new FlowLayout());
JButton previewButton = new JButton("Preview");
JButton executeButton = new JButton("Execute Rename");
JButton clearButton = new JButton("Clear All");
previewButton.addActionListener(e -> previewRename());
executeButton.addActionListener(e -> executeRename());
clearButton.addActionListener(e -> clearAll());
operationsPanel.add(previewButton);
operationsPanel.add(executeButton);
operationsPanel.add(clearButton);
upperPanel.add(new JLabel("Files to Rename:"), BorderLayout.NORTH);
upperPanel.add(tableScrollPane, BorderLayout.CENTER);
upperPanel.add(operationsPanel, BorderLayout.SOUTH);
// Lower panel - Preview
JPanel lowerPanel = new JPanel(new BorderLayout());
previewArea = new JTextArea(10, 80);
previewArea.setEditable(false);
previewArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
JScrollPane previewScrollPane = new JScrollPane(previewArea);
lowerPanel.add(new JLabel("Preview:"), BorderLayout.NORTH);
lowerPanel.add(previewScrollPane, BorderLayout.CENTER);
splitPane.setTopComponent(upperPanel);
splitPane.setBottomComponent(lowerPanel);
add(splitPane, BorderLayout.CENTER);
}
private void createStatusBar() {
statusLabel = new JLabel("Ready");
statusLabel.setBorder(BorderFactory.createEtchedBorder());
add(statusLabel, BorderLayout.SOUTH);
}
private void addFiles() {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setMultiSelectionEnabled(true);
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
int result = fileChooser.showOpenDialog(this);
if (result == JFileChooser.APPROVE_OPTION) {
File[] selectedFiles = fileChooser.getSelectedFiles();
for (File file : selectedFiles) {
try {
renamer.addFile(file);
addFileToTable(file);
} catch (IllegalArgumentException e) {
JOptionPane.showMessageDialog(this, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
}
}
updateStatus();
}
}
private void addFolder() {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int result = fileChooser.showOpenDialog(this);
if (result == JFileChooser.APPROVE_OPTION) {
File directory = fileChooser.getSelectedFile();
// Show filter dialog
AdvancedFileFilter filter = showFilterDialog();
if (filter != null) {
try {
renamer.addFilesFromDirectory(directory, true);
// Apply filter
List<File> filteredFiles = filter.filterFiles(renamer.getFiles());
renamer.clearFiles();
renamer.addFiles(filteredFiles);
refreshFileTable();
updateStatus();
} catch (Exception e) {
JOptionPane.showMessageDialog(this, "Error adding files: " + e.getMessage(),
"Error", JOptionPane.ERROR_MESSAGE);
}
}
}
}
private AdvancedFileFilter showFilterDialog() {
JDialog filterDialog = new JDialog(this, "File Filter", true);
filterDialog.setLayout(new BorderLayout());
JPanel contentPanel = new JPanel(new GridLayout(0, 2, 5, 5));
JTextField extensionField = new JTextField();
JTextField namePatternField = new JTextField();
JTextField minSizeField = new JTextField();
JTextField maxSizeField = new JTextField();
contentPanel.add(new JLabel("Extensions (comma-separated):"));
contentPanel.add(extensionField);
contentPanel.add(new JLabel("Name pattern (regex):"));
contentPanel.add(namePatternField);
contentPanel.add(new JLabel("Min size (bytes):"));
contentPanel.add(minSizeField);
contentPanel.add(new JLabel("Max size (bytes):"));
contentPanel.add(maxSizeField);
JPanel buttonPanel = new JPanel();
JButton okButton = new JButton("OK");
JButton cancelButton = new JButton("Cancel");
okButton.addActionListener(e -> filterDialog.dispose());
cancelButton.addActionListener(e -> {
filterDialog.dispose();
});
buttonPanel.add(okButton);
buttonPanel.add(cancelButton);
filterDialog.add(contentPanel, BorderLayout.CENTER);
filterDialog.add(buttonPanel, BorderLayout.SOUTH);
filterDialog.pack();
filterDialog.setLocationRelativeTo(this);
filterDialog.setVisible(true);
// Build filter based on input
AdvancedFileFilter filter = AdvancedFileFilter.create();
String extensions = extensionField.getText().trim();
if (!extensions.isEmpty()) {
String[] extArray = extensions.split("\\s*,\\s*");
filter.byExtension(extArray);
}
String pattern = namePatternField.getText().trim();
if (!pattern.isEmpty()) {
filter.byNamePattern(pattern);
}
try {
String minSizeStr = minSizeField.getText().trim();
if (!minSizeStr.isEmpty()) {
filter.byMinSize(Long.parseLong(minSizeStr));
}
String maxSizeStr = maxSizeField.getText().trim();
if (!maxSizeStr.isEmpty()) {
filter.byMaxSize(Long.parseLong(maxSizeStr));
}
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(this, "Invalid size format", "Error", JOptionPane.ERROR_MESSAGE);
return null;
}
return filter;
}
private void addFileToTable(File file) {
tableModel.addRow(new Object[]{
file.getName(),
file.getName(),
"Pending",
file.getParent()
});
}
private void refreshFileTable() {
tableModel.setRowCount(0);
for (File file : renamer.getFiles()) {
addFileToTable(file);
}
}
private void clearFiles() {
renamer.clearFiles();
tableModel.setRowCount(0);
updateStatus();
}
private void clearOperations() {
renamer.clearOperations();
previewArea.setText("");
updateStatus();
}
private void clearAll() {
clearFiles();
clearOperations();
}
private void updateStatus() {
statusLabel.setText(String.format("Files: %d | Operations: %d",
renamer.getFileCount(), renamer.getOperationCount()));
}
// Operation dialogs
private void showReplaceDialog() {
JTextField searchField = new JTextField(20);
JTextField replaceField = new JTextField(20);
Object[] message = {
"Search for:", searchField,
"Replace with:", replaceField
};
int option = JOptionPane.showConfirmDialog(this, message, "Replace Text",
JOptionPane.OK_CANCEL_OPTION);
if (option == JOptionPane.OK_OPTION) {
String search = searchField.getText();
String replacement = replaceField.getText();
if (!search.isEmpty()) {
renamer.addReplaceOperation(search, replacement);
updatePreview();
updateStatus();
}
}
}
private void showRegexDialog() {
JTextField regexField = new JTextField(20);
JTextField replaceField = new JTextField(20);
Object[] message = {
"Regular expression:", regexField,
"Replacement:", replaceField
};
int option = JOptionPane.showConfirmDialog(this, message, "Regex Replace",
JOptionPane.OK_CANCEL_OPTION);
if (option == JOptionPane.OK_OPTION) {
String regex = regexField.getText();
String replacement = replaceField.getText();
if (!regex.isEmpty()) {
renamer.addRegexOperation(regex, replacement);
updatePreview();
updateStatus();
}
}
}
private void showPrefixDialog() {
String prefix = JOptionPane.showInputDialog(this, "Enter prefix:", "Add Prefix",
JOptionPane.QUESTION_MESSAGE);
if (prefix != null && !prefix.trim().isEmpty()) {
renamer.addPrefixOperation(prefix.trim());
updatePreview();
updateStatus();
}
}
private void showSuffixDialog() {
String suffix = JOptionPane.showInputDialog(this, "Enter suffix:", "Add Suffix",
JOptionPane.QUESTION_MESSAGE);
if (suffix != null && !suffix.trim().isEmpty()) {
renamer.addSuffixOperation(suffix.trim());
updatePreview();
updateStatus();
}
}
private void showCaseDialog() {
String[] options = {"UPPERCASE", "lowercase", "CamelCase", "Title Case"};
String choice = (String) JOptionPane.showInputDialog(this,
"Select case conversion:", "Change Case",
JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
if (choice != null) {
BatchFileRenamer.CaseType caseType = BatchFileRenamer.CaseType.valueOf(
choice.toUpperCase().replace(" ", "_"));
renamer.addCaseOperation(caseType);
updatePreview();
updateStatus();
}
}
private void showNumberingDialog() {
JTextField prefixField = new JTextField(10);
JTextField suffixField = new JTextField(10);
JSpinner startSpinner = new JSpinner(new SpinnerNumberModel(1, 1, 10000, 1));
JSpinner digitsSpinner = new JSpinner(new SpinnerNumberModel(2, 1, 10, 1));
Object[] message = {
"Prefix:", prefixField,
"Suffix:", suffixField,
"Start number:", startSpinner,
"Number of digits:", digitsSpinner
};
int option = JOptionPane.showConfirmDialog(this, message, "Sequential Numbering",
JOptionPane.OK_CANCEL_OPTION);
if (option == JOptionPane.OK_OPTION) {
String prefix = prefixField.getText();
String suffix = suffixField.getText();
int startNumber = (Integer) startSpinner.getValue();
int digits = (Integer) digitsSpinner.getValue();
renamer.addSequentialNumbering(prefix, suffix, startNumber, digits);
updatePreview();
updateStatus();
}
}
private void showExtensionDialog() {
String newExtension = JOptionPane.showInputDialog(this,
"Enter new extension (with or without dot):", "Change Extension",
JOptionPane.QUESTION_MESSAGE);
if (newExtension != null && !newExtension.trim().isEmpty()) {
renamer.addExtensionChange(newExtension.trim());
updatePreview();
updateStatus();
}
}
private void updatePreview() {
List<BatchFileRenamer.RenameResult> preview = renamer.previewRename();
StringBuilder sb = new StringBuilder();
sb.append("PREVIEW - Changes to be made:\n\n");
for (BatchFileRenamer.RenameResult result : preview) {
sb.append(String.format("%-30s -> %-30s\n",
result.getOriginalFile().getName(),
result.getNewFile().getName()));
}
previewArea.setText(sb.toString());
}
private void previewRename() {
if (renamer.getFileCount() == 0) {
JOptionPane.showMessageDialog(this, "No files to rename", "Warning",
JOptionPane.WARNING_MESSAGE);
return;
}
updatePreview();
}
private void executeRename() {
if (renamer.getFileCount() == 0) {
JOptionPane.showMessageDialog(this, "No files to rename", "Warning",
JOptionPane.WARNING_MESSAGE);
return;
}
if (renamer.getOperationCount() == 0) {
JOptionPane.showMessageDialog(this, "No operations defined", "Warning",
JOptionPane.WARNING_MESSAGE);
return;
}
int confirm = JOptionPane.showConfirmDialog(this,
"Are you sure you want to rename " + renamer.getFileCount() + " files?",
"Confirm Rename", JOptionPane.YES_NO_OPTION);
if (confirm == JOptionPane.YES_OPTION) {
List<BatchFileRenamer.RenameResult> results = renamer.executeRename();
int successCount = 0;
int errorCount = 0;
StringBuilder resultText = new StringBuilder();
resultText.append("RENAME RESULTS:\n\n");
for (BatchFileRenamer.RenameResult result : results) {
switch (result.getStatus()) {
case SUCCESS:
successCount++;
resultText.append("✓ ");
break;
case FAILED:
case ERROR:
errorCount++;
resultText.append("✗ ");
break;
default:
resultText.append("? ");
}
resultText.append(String.format("%s -> %s",
result.getOriginalFile().getName(),
result.getNewFile() != null ? result.getNewFile().getName() : "N/A"));
if (result.getErrorMessage() != null) {
resultText.append(" [Error: ").append(result.getErrorMessage()).append("]");
}
resultText.append("\n");
}
resultText.append("\nSummary: ").append(successCount)
.append(" successful, ").append(errorCount).append(" failed");
previewArea.setText(resultText.toString());
refreshFileTable();
JOptionPane.showMessageDialog(this,
String.format("Rename completed: %d successful, %d failed",
successCount, errorCount),
"Rename Complete", JOptionPane.INFORMATION_MESSAGE);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeel());
} catch (Exception e) {
e.printStackTrace();
}
new BatchFileRenamerGUI();
});
}
}
Command Line Interface
CLI Version
import java.io.*;
import java.util.*;
public class BatchFileRenamerCLI {
private final BatchFileRenamer renamer;
private final Scanner scanner;
public BatchFileRenamerCLI() {
this.renamer = new BatchFileRenamer();
this.scanner = new Scanner(System.in);
}
public void start() {
System.out.println("=== Batch File Renamer CLI ===");
System.out.println();
boolean running = true;
while (running) {
showMainMenu();
String choice = scanner.nextLine().trim();
switch (choice) {
case "1":
addFilesInteractive();
break;
case "2":
addFolderInteractive();
break;
case "3":
showOperationsMenu();
break;
case "4":
previewRename();
break;
case "5":
executeRename();
break;
case "6":
showCurrentState();
break;
case "7":
clearAll();
break;
case "0":
running = false;
break;
default:
System.out.println("Invalid choice. Please try again.");
}
}
System.out.println("Goodbye!");
}
private void showMainMenu() {
System.out.println("\n--- Main Menu ---");
System.out.println("1. Add files");
System.out.println("2. Add folder");
System.out.println("3. Operations");
System.out.println("4. Preview rename");
System.out.println("5. Execute rename");
System.out.println("6. Show current state");
System.out.println("7. Clear all");
System.out.println("0. Exit");
System.out.print("Choose an option: ");
}
private void addFilesInteractive() {
System.out.print("Enter file paths (comma-separated): ");
String input = scanner.nextLine();
String[] filePaths = input.split("\\s*,\\s*");
int addedCount = 0;
for (String path : filePaths) {
File file = new File(path.trim());
if (file.exists() && file.isFile()) {
renamer.addFile(file);
addedCount++;
System.out.println("Added: " + file.getName());
} else {
System.out.println("File not found: " + path);
}
}
System.out.println("Added " + addedCount + " files.");
}
private void addFolderInteractive() {
System.out.print("Enter folder path: ");
String path = scanner.nextLine().trim();
File folder = new File(path);
if (!folder.exists() || !folder.isDirectory()) {
System.out.println("Folder not found: " + path);
return;
}
System.out.print("Recursive (y/n)? ");
boolean recursive = scanner.nextLine().trim().equalsIgnoreCase("y");
try {
renamer.addFilesFromDirectory(folder, recursive);
System.out.println("Added " + renamer.getFileCount() + " files from folder.");
} catch (Exception e) {
System.out.println("Error adding files: " + e.getMessage());
}
}
private void showOperationsMenu() {
boolean inMenu = true;
while (inMenu) {
System.out.println("\n--- Operations Menu ---");
System.out.println("1. Replace text");
System.out.println("2. Regex replace");
System.out.println("3. Add prefix");
System.out.println("4. Add suffix");
System.out.println("5. Change case");
System.out.println("6. Sequential numbering");
System.out.println("7. Change extension");
System.out.println("8. Remove characters");
System.out.println("9. Show current operations");
System.out.println("0. Back to main menu");
System.out.print("Choose an option: ");
String choice = scanner.nextLine().trim();
switch (choice) {
case "1":
addReplaceOperation();
break;
case "2":
addRegexOperation();
break;
case "3":
addPrefixOperation();
break;
case "4":
addSuffixOperation();
break;
case "5":
addCaseOperation();
break;
case "6":
addNumberingOperation();
break;
case "7":
addExtensionOperation();
break;
case "8":
addRemoveCharsOperation();
break;
case "9":
showCurrentOperations();
break;
case "0":
inMenu = false;
break;
default:
System.out.println("Invalid choice.");
}
}
}
private void addReplaceOperation() {
System.out.print("Enter text to search for: ");
String search = scanner.nextLine();
System.out.print("Enter replacement text: ");
String replacement = scanner.nextLine();
renamer.addReplaceOperation(search, replacement);
System.out.println("Added replace operation.");
}
private void addRegexOperation() {
System.out.print("Enter regular expression: ");
String regex = scanner.nextLine();
System.out.print("Enter replacement: ");
String replacement = scanner.nextLine();
renamer.addRegexOperation(regex, replacement);
System.out.println("Added regex operation.");
}
private void addPrefixOperation() {
System.out.print("Enter prefix: ");
String prefix = scanner.nextLine();
renamer.addPrefixOperation(prefix);
System.out.println("Added prefix operation.");
}
private void addSuffixOperation() {
System.out.print("Enter suffix: ");
String suffix = scanner.nextLine();
renamer.addSuffixOperation(suffix);
System.out.println("Added suffix operation.");
}
private void addCaseOperation() {
System.out.println("Case options:");
System.out.println("1. UPPERCASE");
System.out.println("2. lowercase");
System.out.println("3. CamelCase");
System.out.println("4. Title Case");
System.out.print("Choose case type: ");
String choice = scanner.nextLine().trim();
BatchFileRenamer.CaseType caseType;
switch (choice) {
case "1": caseType = BatchFileRenamer.CaseType.UPPERCASE; break;
case "2": caseType = BatchFileRenamer.CaseType.LOWERCASE; break;
case "3": caseType = BatchFileRenamer.CaseType.CAMELCASE; break;
case "4": caseType = BatchFileRenamer.CaseType.TITLE_CASE; break;
default:
System.out.println("Invalid choice. Using UPPERCASE.");
caseType = BatchFileRenamer.CaseType.UPPERCASE;
}
renamer.addCaseOperation(caseType);
System.out.println("Added case operation.");
}
private void addNumberingOperation() {
System.out.print("Enter prefix (optional): ");
String prefix = scanner.nextLine();
System.out.print("Enter suffix (optional): ");
String suffix = scanner.nextLine();
System.out.print("Start number (default 1): ");
String startStr = scanner.nextLine();
System.out.print("Number of digits (default 2): ");
String digitsStr = scanner.nextLine();
int start = startStr.isEmpty() ? 1 : Integer.parseInt(startStr);
int digits = digitsStr.isEmpty() ? 2 : Integer.parseInt(digitsStr);
renamer.addSequentialNumbering(prefix, suffix, start, digits);
System.out.println("Added numbering operation.");
}
private void addExtensionOperation() {
System.out.print("Enter new extension: ");
String extension = scanner.nextLine();
renamer.addExtensionChange(extension);
System.out.println("Added extension change operation.");
}
private void addRemoveCharsOperation() {
System.out.print("Enter characters to remove: ");
String chars = scanner.nextLine();
renamer.addCustomOperation(new RemoveCharactersOperation(chars));
System.out.println("Added remove characters operation.");
}
private void showCurrentOperations() {
System.out.println("\nCurrent operations:");
// Note: In a real implementation, you'd want to store operation descriptions
System.out.println("Operations count: " + renamer.getOperationCount());
}
private void previewRename() {
if (renamer.getFileCount() == 0) {
System.out.println("No files to rename.");
return;
}
List<BatchFileRenamer.RenameResult> preview = renamer.previewRename();
System.out.println("\n--- Preview ---");
for (BatchFileRenamer.RenameResult result : preview) {
System.out.printf("%s -> %s\n",
result.getOriginalFile().getName(),
result.getNewFile().getName());
}
}
private void executeRename() {
if (renamer.getFileCount() == 0) {
System.out.println("No files to rename.");
return;
}
if (renamer.getOperationCount() == 0) {
System.out.println("No operations defined.");
return;
}
System.out.print("Are you sure you want to rename " + renamer.getFileCount() +
" files? (y/n): ");
String confirm = scanner.nextLine().trim();
if (confirm.equalsIgnoreCase("y")) {
List<BatchFileRenamer.RenameResult> results = renamer.executeRename();
int successCount = 0;
int errorCount = 0;
System.out.println("\n--- Results ---");
for (BatchFileRenamer.RenameResult result : results) {
switch (result.getStatus()) {
case SUCCESS:
successCount++;
System.out.printf("✓ %s -> %s\n",
result.getOriginalFile().getName(),
result.getNewFile().getName());
break;
case FAILED:
case ERROR:
errorCount++;
System.out.printf("✗ %s -> %s",
result.getOriginalFile().getName(),
result.getNewFile() != null ? result.getNewFile().getName() : "N/A");
if (result.getErrorMessage() != null) {
System.out.print(" [Error: " + result.getErrorMessage() + "]");
}
System.out.println();
break;
}
}
System.out.printf("\nSummary: %d successful, %d failed\n", successCount, errorCount);
}
}
private void showCurrentState() {
System.out.println("\n--- Current State ---");
System.out.println("Files: " + renamer.getFileCount());
System.out.println("Operations: " + renamer.getOperationCount());
if (renamer.getFileCount() > 0) {
System.out.println("\nFiles:");
for (File file : renamer.getFiles()) {
System.out.println(" " + file.getName());
}
}
}
private void clearAll() {
renamer.clearFiles();
renamer.clearOperations();
System.out.println("Cleared all files and operations.");
}
public static void main(String[] args) {
new BatchFileRenamerCLI().start();
}
}
Usage Examples
Basic Usage Examples
public class BatchFileRenamerExamples {
public static void main(String[] args) {
// Example 1: Simple text replacement
example1();
// Example 2: Multiple operations
example2();
// Example 3: Sequential numbering
example3();
// Example 4: Using filters
example4();
}
private static void example1() {
System.out.println("=== Example 1: Simple Text Replacement ===");
BatchFileRenamer renamer = new BatchFileRenamer();
// Add some test files (in real usage, these would be actual files)
renamer.addFile(new File("photo1.jpg"));
renamer.addFile(new File("photo2.jpg"));
renamer.addFile(new File("photo3.jpg"));
// Replace "photo" with "image"
renamer.addReplaceOperation("photo", "image");
// Preview changes
List<BatchFileRenamer.RenameResult> preview = renamer.previewRename();
for (BatchFileRenamer.RenameResult result : preview) {
System.out.println(result.getOriginalFile().getName() + " -> " +
result.getNewFile().getName());
}
}
private static void example2() {
System.out.println("\n=== Example 2: Multiple Operations ===");
BatchFileRenamer renamer = new BatchFileRenamer();
renamer.addFile(new File("MY_DOCUMENT_001.txt"));
renamer.addFile(new File("ANOTHER_FILE_002.doc"));
// Convert to lowercase
renamer.addCaseOperation(BatchFileRenamer.CaseType.LOWERCASE);
// Replace underscores with spaces
renamer.addReplaceOperation("_", " ");
// Add prefix
renamer.addPrefixOperation("processed_");
List<BatchFileRenamer.RenameResult> preview = renamer.previewRename();
for (BatchFileRenamer.RenameResult result : preview) {
System.out.println(result.getOriginalFile().getName() + " -> " +
result.getNewFile().getName());
}
}
private static void example3() {
System.out.println("\n=== Example 3: Sequential Numbering ===");
BatchFileRenamer renamer = new BatchFileRenamer();
renamer.addFile(new File("image.jpg"));
renamer.addFile(new File("image.jpg"));
renamer.addFile(new File("image.jpg"));
// Add sequential numbering
renamer.addSequentialNumbering("vacation_", "", 1, 3);
List<BatchFileRenamer.RenameResult> preview = renamer.previewRename();
for (BatchFileRenamer.RenameResult result : preview) {
System.out.println(result.getOriginalFile().getName() + " -> " +
result.getNewFile().getName());
}
}
private static void example4() {
System.out.println("\n=== Example 4: Using Filters ===");
// Create a directory with test files
File testDir = new File("test_files");
testDir.mkdir();
try {
// Create some test files
new File(testDir, "document1.pdf").createNewFile();
new File(testDir, "image1.jpg").createNewFile();
new File(testDir, "image2.png").createNewFile();
new File(testDir, "data.txt").createNewFile();
// Use advanced filter
AdvancedFileFilter filter = AdvancedFileFilter.create()
.byExtension("jpg", "png")
.byNameContains("image");
File[] allFiles = testDir.listFiles();
List<File> filteredFiles = filter.filterFiles(allFiles);
System.out.println("Filtered files:");
for (File file : filteredFiles) {
System.out.println(" " + file.getName());
}
// Clean up
for (File file : allFiles) {
file.delete();
}
testDir.delete();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Features Summary
This Batch File Renamer provides:
- Multiple Renaming Strategies:
- Text replacement
- Regex-based replacement
- Prefix/suffix addition
- Case conversion
- Sequential numbering
- Extension changes
- Character removal
- Truncation
- File Management:
- Add individual files
- Add entire directories (recursive or not)
- Advanced file filtering
- Conflict resolution
- Safety Features:
- Preview mode
- Operation validation
- Error handling
- Undo capability (through backup)
- Multiple Interfaces:
- Graphical user interface (Swing)
- Command-line interface
- Programmatic API
- Extensibility:
- Custom operation interface
- Pluggable filters
- Modular design
The tool is suitable for both simple file renaming tasks and complex batch processing scenarios.