取得檔案副檔名是檔案處理的基礎操作。本文整理三種主流做法:正則表達式、字串截取、現代 NIO API,並比較其優缺點與適用場景,附上完整可執行程式碼。
適合需驗證副檔名格式、支援多種命名規則的情境:
import java.util.regex.*;
public class RegexExtension {
public static String getExtension(String fileName) {
// 匹配最後一個點之後的英文字母
String regex = ".+\\.([a-zA-Z]+)$";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(fileName);
if (matcher.find()) {
return matcher.group(1).toLowerCase();
}
return "";
}
public static void main(String[] args) {
System.out.println(getExtension("image.jpg")); // jpg
System.out.println(getExtension("archive.tar.gz")); // gz
System.out.println(getExtension("README")); // 空字串
System.out.println(getExtension(".hidden")); // 空字串
}
}
利用 lastIndexOf('.') 定位最後一個點號位置:
public class SubstringExtension {
public static String getExtension(String fileName) {
if (fileName == null) return "";
int dotIndex = fileName.lastIndexOf('.');
// 條件:有點號、點號不在第一位、點號不在最後
if (dotIndex > 0 && dotIndex < fileName.length() - 1) {
return fileName.substring(dotIndex + 1).toLowerCase();
}
return "";
}
// 替代寫法:指定結束位置
public static String getExtensionV2(String fileName) {
int dotIndex = fileName.lastIndexOf('.');
if (dotIndex > 0) {
return fileName.substring(dotIndex + 1, fileName.length()).toLowerCase();
}
return "";
}
}
使用 Path 物件處理路徑,語意清晰且跨平台:
import java.nio.file.*;
public class NioExtension {
public static String getExtension(String fileName) {
Path path = Paths.get(fileName);
String name = path.getFileName().toString(); // 僅取檔名部分
int dotIndex = name.lastIndexOf('.');
if (dotIndex > 0 && dotIndex < name.length() - 1) {
return name.substring(dotIndex + 1).toLowerCase();
}
return "";
}
// 實務上常搭配 Files.probeContentType 偵測 MIME 類型
public static void detectType(Path file) throws IOException {
String mime = Files.probeContentType(file);
System.out.println("MIME 類型:" + mime);
}
}
| 維度 | 正則表達式 | substring | NIO Path |
|---|---|---|---|
| 可讀性 | 中等 | 高 | 高 |
| 效能 | 較慢(編譯匹配) | 最快 | 快 |
| 功能性 | 可驗證格式 | 單純截取 | 路徑處理完整 |
| 適用場景 | 複雜命名規則 | 一般用途、高頻呼叫 | 現代專案、路徑操作 |
| 邊界處理 | 需自行設計 pattern | 需手動判斷索引 | getFileName() 自動處理路徑 |
public class EdgeCases {
public static void main(String[] args) {
String[] tests = {
"normal.txt",
"archive.tar.gz",
".gitignore",
"README",
"config.",
".hidden.conf",
"path/to/file.java",
null
};
for (String f : tests) {
System.out.printf("%-20s -> '%s'%n", f, getExt(f));
}
}
static String getExt(String f) {
if (f == null) return "null輸入";
int i = f.lastIndexOf('.');
return (i > 0 && i < f.length() - 1) ? f.substring(i + 1) : "(無副檔名)";
}
}
normal.txt -> 'txt' archive.tar.gz -> 'gz' .gitignore -> '(無副檔名)' README -> '(無副檔名)' config. -> '(無副檔名)' .hidden.conf -> 'conf' path/to/file.java -> 'java' null輸入 -> 'null輸入'
substring + lastIndexOf,效能最好、程式碼最簡潔Path 物件,配合 FilenameUtils.getExtension() (Apache Commons IO) 更穩健Set<String> allowed = Set.of("jpg","png","pdf") 驗證