本篇教學文章示範如何使用Java不透過第三方套件來判斷檔案的副檔名,以及檔案類型,只需要Java 7的NIO就可以達成,再加上Java 8的Optional與Stream API來更優雅的處理。使用原生的API可以避免一些問題,例如執行時還需要第三方套件、第三方套件還包含太多用不上的API徒增檔案大小、第三方套件不更新可能有漏洞等麻煩。
取得副檔名
副檔名是檔案名稱中最後一個.
後面的文字,通常是英文與數字,例如.jpg
、.mp3
、.txt
等。雖然使用org.apache.commons.io.FilenameUtils
可以找到副檔名,但我們目標是你複製以下程式碼就可以直接使用,不用再安裝第三方套件。
找出.的位置
這邊只透過Java的String內建的方法來尋找副檔名,效率也不錯。
// 副檔名預設為空字串
String extension = "";
// 我們要判斷的檔案名稱
String filename = "klab.tw.txt";
// 尋找最後一個.的位置,沒找到會回傳 -1
int idx = filename.lastIndexOf(".");
if(idx >= 0) {
// 使用substring取得副檔名,會得到 txt
extension = filename.substring(idx + 1);
}
使用Optional寫成完整版
Java 8開始增加一系列Stream API,我們重寫然後寫成一個Class,可以直接呼叫使用。
import java.util.Optional;
/**
* Create by https://klab.tw
*/
public class FileTools {
/**
* 從檔案名稱判斷副檔名。
* @param filename 檔案名稱
* @param orElse 找不到的時候返回的預設值,可為null
* @return 副檔名
*/
public static String getExtension(String filename, String orElse) {
return Optional.ofNullable(filename)
.filter(s -> s.contains("."))
.map(s -> s.substring(s.lastIndexOf(".") + 1))
.orElse(orElse);
}
}
使用方法如下。
FileTools.getExtension("klab.tw.txt", "");
// 返回:txt
取得檔案類型
在這邊我們使用Java 7開始內建的NIO API,使用Files
直接透過副檔名判斷檔案類型,雖然在Windows檔案總管在預設情況下不能直接更改副檔名,但是副檔名是人為決定的,而且很好修改,不能作為判斷檔案類型的唯一方式,但還是可以作為參考。
使用Path與Files
使用java.nio.file.Path
建立Path物件,然後透過java.nio.file.Files
內建的方法即可判斷。找不到的時候會回傳null,而且需要處理IOException。
String filename = "klab.tw.txt";
Path path = Path.of(filename);
String mime = Files.probeContentType(path);
使用Optional寫成完整版
以下搭配Java 8的Stream API,寫可以直接呼叫使用、不用管IOException的完整版。
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;
/**
* Create by https://klab.tw
*/
public class FileTools {
/**
* 透過檔案副檔名判斷檔案類型。
* @param filename 檔案名稱
* @param orElse 找不到的時候返回的預設值,可為null
* @return 檔案類型
*/
public static String getContentType(String filename, String orElse) {
return Optional.ofNullable(filename)
.map(s -> Path.of(s))
.map(p -> {
try {
return Files.probeContentType(p);
} catch (Throwable e) {
return null;
}
})
.orElse(orElse);
}
}
使用方法如下。
FileTools.getContentType("klab.tw.txt", "");
// 返回:text/plain