本篇教學文章示範如何使用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