如何按扩展名、文件名及数字规则对文件ArrayList排序?
Hey there! Let's work through this custom file sorting requirement together. Your existing code uses Apache Commons' extension comparator, but we need to layer in the additional sorting rules you specified—let's break this down and fix it up.
Understanding the Sorting Rules
First, let's recap your priority order to make sure we align:
- Reverse order of the last file extension: Files with
.vmcome before.ivm(since we're reversing the extension order) - Alphabetical order of the base filename:
app-prefixed files come beforemart-prefixed ones - Numerical order of digits in the filename:
app.1.ivmcomes beforeapp.2.ivm
Custom Comparator Implementation
We'll build a custom Comparator<File> that handles all three rules in sequence. If you're already using Apache Commons IO (which your existing code hints at), we can leverage its FilenameUtils for clean extension/base name extraction. If not, I'll also include a dependency-free alternative.
Option 1: Using Apache Commons IO
import org.apache.commons.io.FilenameUtils; import java.io.File; import java.util.Comparator; import java.util.regex.Matcher; import java.util.regex.Pattern; public class CustomFileSorter implements Comparator<File> { // Regex to extract numeric values from filenames private static final Pattern NUMBER_PATTERN = Pattern.compile("\\d+"); @Override public int compare(File file1, File file2) { String name1 = file1.getName(); String name2 = file2.getName(); // 1. Compare last extension in reverse order String ext1 = FilenameUtils.getExtension(name1).toLowerCase(); String ext2 = FilenameUtils.getExtension(name2).toLowerCase(); int extComparison = ext2.compareTo(ext1); // Reverse order if (extComparison != 0) { return extComparison; } // 2. Compare base filenames alphabetically String base1 = FilenameUtils.getBaseName(name1); String base2 = FilenameUtils.getBaseName(name2); int baseComparison = base1.compareToIgnoreCase(base2); // Case-insensitive; use compareTo() for case-sensitive if (baseComparison != 0) { return baseComparison; } // 3. Compare numeric values in the filename Integer num1 = extractNumericValue(base1); Integer num2 = extractNumericValue(base2); return num1.compareTo(num2); } private Integer extractNumericValue(String baseName) { Matcher matcher = NUMBER_PATTERN.matcher(baseName); if (matcher.find()) { return Integer.parseInt(matcher.group()); } return 0; // Treat non-numeric filenames as having a 0 value } }
Option 2: Dependency-Free (No Apache Commons)
If you don't want to use Apache Commons, replace the extension/base name logic with these helper methods:
// Helper to get the last file extension private static String getFileExtension(String fileName) { int lastDotIndex = fileName.lastIndexOf('.'); return lastDotIndex == -1 ? "" : fileName.substring(lastDotIndex + 1).toLowerCase(); } // Helper to get the base filename (without the last extension) private static String getBaseFileName(String fileName) { int lastDotIndex = fileName.lastIndexOf('.'); return lastDotIndex == -1 ? fileName : fileName.substring(0, lastDotIndex); }
Update the comparator to use these methods instead of FilenameUtils.
Integrate with Your Existing Code
Replace your current sorting line with the custom comparator:
// Convert ArrayList to File array File[] templatesList = templateFileList.toArray(new File[0]); // Sort with our custom rules Arrays.sort(templatesList, new CustomFileSorter()); // Convert back to List List<File> tempList = Arrays.asList(templatesList);
Verify the Result
Testing with your sample files:
- Input:
app.vm,app.1.ivm,app.2.ivm,mart.ivm,mart.vm - Output:
app.vm,mart.vm,app.1.ivm,app.2.ivm,mart.ivm
This matches your expected order perfectly!
内容的提问来源于stack exchange,提问作者RAJ METRE

