iT邦幫忙

0

應用系統建置前準備工具 - FileUtils 檔案工具

  • 分享至 

  • xImage
  •  

FileUtils 檔案工具類別

概述

FileUtils 是一個提供檔案操作的工具類別。此類別設計為靜態工具類別,提供檔案讀寫、格式判斷、路徑處理等功能,特別適合處理檔案相關的各種操作需求。

專案相關程式

  • GlobalConstants
  • TypeConvert
  • CommUtils
  • DateUtils

第三方元件(Dependency)

  • org.apache.commons.io
  • org.apache.commons.lang3
  • lombok
  • spring-core

主要功能

1. 檔案轉換操作

檔案與 byte[] 互轉

// 檔案轉 byte[]
byte[] data = FileUtils.fileToByteArray("data.txt");

// byte[] 轉檔案(指定路徑)
String path = FileUtils.byteArrayToFile(data, "output.txt");

// byte[] 轉臨時檔案
String tempPath = FileUtils.byteArrayToFileTemp(data);

檔案與字串列表互轉

// 檔案轉字串列表
List<String> lines = FileUtils.fileToStringArrayList("input.txt");

// 字串列表轉檔案
FileUtils.stringArrayListToFile(lines, "output.txt");

// 附加字串到檔案
FileUtils.appendStringToFile("新的一行", "log.txt");

2. 檔案路徑處理

路徑操作

// 取得檔名(不含路徑)
String name = FileUtils.getName("c:/folder/file.txt");  // "file.txt"

// 取得檔案基本名稱(不含副檔名)
String base = FileUtils.getFileNameBase("document.old.txt");  // "document"

// 取得不含最後副檔名的檔名
String noExt = FileUtils.getFileNameNotSuffix("doc.ver1.txt");  // "doc.ver1"

3. 檔案搜尋

專案內檔案搜尋

// 在 classpath 中搜尋檔案
String path = FileUtils.getFileAbsolutePathInClass("config.properties");

// 在指定前綴路徑下搜尋
String configPath = FileUtils.getFileAbsolutePath("config/", "app.properties");

目錄檔案搜尋

// 搜尋目錄下所有檔案
List<String> allFiles = FileUtils.getFiles("c:/data", "*");

// 搜尋特定副檔名檔案
List<String> txtFiles = FileUtils.getFiles("c:/data", ".txt");

4. 檔案格式判斷

圖片格式判斷

// 依據檔案內容判斷圖片格式
byte[] imageData = FileUtils.fileToByteArray("image.jpg");
String format = FileUtils.getFileExtendName(imageData);  // "jpg", "png" 等

5. 檔案管理

檔案操作

// 檢查檔案是否存在
boolean exists = FileUtils.checkFileExist("data.txt");

// 刪除檔案
boolean deleted = FileUtils.deleteFile("temp.txt");

// 產生唯一檔名
String uniquePath = FileUtils.getUniqFileName("upload_");

重要注意事項

  1. 檔案操作

    • 所有檔案操作都可能拋出 IOException
    • 自動關閉資源串流
    • 大檔案操作時注意記憶體使用
  2. 路徑處理

    • 支援跨平台路徑分隔符
    • 自動處理空值和非法字元
    • 統一使用絕對路徑
  3. 搜尋功能

    • 支援遞迴搜尋子目錄
    • 可使用萬用字元過濾
    • 注意檔案系統權限
  4. 格式判斷

    • 使用檔案特徵碼判斷格式
    • 支援主要圖片格式
    • 預設值為保守判斷

單元測試範例

以下測試範例示範 FileUtils 常用操作:

1. 檔案與 byte[] 互轉

@Test
void testFileToByteAndBack(@TempDir Path tempDir) throws Exception {
   Path file = tempDir.resolve("test.txt");
   Files.write(file, "hello".getBytes(StandardCharsets.UTF_8));

   byte[] data = FileUtils.fileToByteArray(file.toString());
   assertArrayEquals("hello".getBytes(StandardCharsets.UTF_8), data);

   String out = FileUtils.byteArrayToFile(data, tempDir.resolve("out.txt").toString());
   assertTrue(new File(out).exists());
}

2. 字串列表與檔案操作

@Test
void testStringListToFileAndRead(@TempDir Path tempDir) throws Exception {
   List<String> lines = Arrays.asList("a","b","c");
   String path = tempDir.resolve("lines.txt").toString();
   FileUtils.stringArrayListToFile(lines, path);

   List<String> read = FileUtils.fileToStringArrayList(path);
   assertEquals(lines, read);
}

3. 路徑與存在性

@Test
void testGetNameAndExistence(@TempDir Path tempDir) throws Exception {
   Path p = tempDir.resolve("folder").resolve("file.txt");
   Files.createDirectories(p.getParent());
   Files.write(p, "x".getBytes());

   assertEquals("file.txt", FileUtils.getName(p.toString()));
   assertTrue(FileUtils.checkFileExist(p.toString()));
   assertTrue(FileUtils.deleteFile(p.toString()));
}

測試說明

  • 測試檔案與位元組互轉
  • 測試檔案內容讀寫
  • 測試路徑處理與存在性檢查

程式碼 FileUtils.java

package tw.lewishome.webapp.base.utility.common;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.UUID;

import tw.lewishome.webapp.GlobalConstants;

import org.apache.commons.io.IOUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;

/**
 * 檔案工具類 (FileUtils)
 *
 *
 * 本類別提供一組同步與非同步常用的檔案處理工具方法,包含:
 * 檔案讀寫、路徑/檔名處理、檔案格式判斷、byte[] 與文字列的互轉,以及專案內資源檔案搜尋等。
 * 設計上以靜態方法提供便利呼叫,適合在 Service、Controller 或測試環境中重複使用。
 *
 *
 * <h2>主要功能</h2>
 * <ul>
 *   <li>檔案與 byte[] 互轉(讀取、寫入、暫存檔案)</li>
 *   <li>文字清單(List&lt;String&gt;)與檔案互轉</li>
 *   <li>專案 classpath 內檔案搜尋</li>
 *   <li>檔案存在性檢查、刪除、列出目錄下檔案</li>
 *   <li>判斷圖片 / 多媒體檔案類型</li>
 * </ul>
 *
 * <h2>設計注意</h2>
 * <ul>
 *   <li>此為工具類(utility),所有方法皆為 static,且不允許實體化。</li>
 *   <li>檔案操作涉及 IO,方法會拋出 IOException,呼叫端應妥善處理或轉換為應用層例外。</li>
 *   <li>部分方法使用外部工具類(CommUtils、DateUtils、TypeConvert、IOUtils),請確保對應工具類可用。</li>
 * </ul>
 *
 *
 * @author Lewis
 */
@Slf4j
public class FileUtils {
   /** Private constructor to prevent instantiation */
    private FileUtils() {
        throw new IllegalStateException("This is a utility class and cannot be instantiated");
    }

    /**
     * Constant
     * <code>FILENAME_PATTERN="[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+"</code>
     */
    protected static final String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";

    /** image file extensions List */
    protected static final List<String> IMAGE_EXTENSION = new ArrayList<>(
            Arrays.asList("bmp", "gif", "jpg", "jpeg", "png"));

    /** Flash file extensions List */
    protected static final List<String> FLASH_EXTENSION = new ArrayList<>(Arrays.asList("swf", "flv"));

    /** Media file extensions List */
    protected static final List<String> MEDIA_EXTENSION = new ArrayList<>(
            Arrays.asList("swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg", "asf", "rm", "rmvb"));
    /** video file extensions List */
    protected static final List<String> VIDEO_EXTENSION = new ArrayList<>(Arrays.asList("mp4", "avi", "rmvb"));

    /** Allow PDF file extensions List */
    protected static final List<String> PDF_EXTENSION = new ArrayList<>(Arrays.asList("pdf"));

    /** Allow Excel file extensions List */
    protected static final List<String> EXCEL_EXTENSION = new ArrayList<>(
            Arrays.asList("xlsx", "xls", "xlsm", "xlsb", "xltx", "xltm"));

    /** Allow Word file extensions List */
    protected static final List<String> WORD_EXTENSION = new ArrayList<>(
            Arrays.asList("doc", "docx", "docm", "dot", "dotx", "dotm", "rtf", "txt", "wll"));

    // ====================== File 轉換相關 ======================
    /**
     * 將指定檔案內容寫入到給定的 {@link OutputStream}。
     *方法會從磁碟讀取 {@code filePath} 指向的檔案並逐段寫入到傳入的 {@code outputStream}。
     * 最後會關閉 {@code outputStream}(透過 IOUtils.close)。 
     *
     * @param outputStream 輸出資料流,呼叫端可傳入 Response 的 OutputStream 或 FileOutputStream
     * @param filePath     要讀取的檔案絕對路徑
     * @throws java.io.IOException 若讀取或寫入發生 IO 錯誤
     * @throws java.io.FileNotFoundException 當指定檔案不存在時拋出
     */
    public static void streamToFile(OutputStream outputStream, String filePath) throws IOException {
        // FileInputStream fileInputStream = null;
        File file = new File(filePath);
        if (!file.exists()) {
            throw new FileNotFoundException(filePath);
        }
        try (FileInputStream fileInputStream = new FileInputStream(file)) {
            byte[] b = new byte[1024];
            int length;
            while ((length = fileInputStream.read(b)) > 0) {
                outputStream.write(b, 0, length);
            }
        } finally {
            IOUtils.close(outputStream);
        }
    }

    /**
     * 將檔案讀取為 {@link InputStream}。
     *實作上會先以 {@link #fileToByteArray(String)} 讀出全部位元組,然後回傳一個包裝於記憶體的 {@link ByteArrayInputStream}。
     * 適用於檔案不大於可用記憶體時的情境。 
     *
     * @param filePath 要讀取的檔案路徑
     * @return 讀取到的 {@link InputStream}
     * @throws IOException IOException 當讀取檔案失敗時拋出
     */
    public static InputStream fileToInputStream(String filePath) throws IOException {

        byte[] result = fileToByteArray(filePath);
        result = Arrays.copyOf(result, result.length);
        return new ByteArrayInputStream(result);
    }

    /**
     * 讀取指定檔案並回傳其位元組陣列(byte[])。
     *
     * @param filePathString 要讀取的檔案路徑
     * @return 檔案內容之 byte[]
     * @throws java.io.IOException 若檔案不存在或讀取失敗
     */
    public static byte[] fileToByteArray(String filePathString) throws IOException {

        Path filePath = Paths.get(filePathString);
        return Files.readAllBytes(filePath);
    }

    /**
     * 將 byte[] 寫入一個臨時檔案並回傳產生之唯一檔名(含路徑)。
     *
     * @param inByteArray 欲寫入的位元組陣列
     * @return 寫入後之檔案路徑
     * @throws java.io.IOException 若寫入失敗
     */
    public static String byteArrayToFileTemp(byte[] inByteArray) throws IOException {

        return byteArrayToFile(inByteArray, "");
    }

    /**
     * 將位元組陣列寫入指定檔案路徑,若傳入之 {@code filePath} 為空白則產生唯一檔名並寫入。
     *
     * @param inByteArray 欲寫入的 byte[]
     * @param filePath    目標檔案路徑,若為空會以 {@link #getUniqFileName(String)} 生成暫存檔
     * @return 最終寫入的檔案路徑
     * @throws java.io.IOException 若寫入 / 檔案建立失敗
     */
    public static String byteArrayToFile(byte[] inByteArray, String filePath) throws IOException {
        if (StringUtils.isBlank(filePath)) {
            filePath = getUniqFileName("UniqFile_");
        }
        try (FileOutputStream fileOutputStream = new FileOutputStream(filePath)) {
            fileOutputStream.write(inByteArray);
        }
        return filePath;
    }

    // ===================== String Array List 轉換相關 ======================
    /**
     * 將文字列清單(List&lt;String&gt;)寫入檔案,每一列換行。
     *
     * @param inStringArray 欲寫入之文字清單
     * @param filePath      目標檔案路徑
     * @throws java.io.IOException 當寫入失敗時拋出
     */
    public static void stringArrayListToFile(List<String> inStringArray, String filePath) throws IOException {
        byte[] bytes = TypeConvert.stringArrayListToByte(inStringArray);
        byteArrayToFile(bytes, filePath);
    }

     /**
     * 將文字加入檔案並換行。
     *
     * @param inString 欲寫入之文字清單
     * @param filePath      目標檔案路徑
     * @throws java.io.IOException 當寫入失敗時拋出
     */
    public static void appendStringToFile(String inString, String filePath) throws IOException {
        Files.write(Paths.get(filePath), inString.getBytes(), StandardOpenOption.APPEND);
    }


    /**
     * 讀取檔案並將內容以行為單位轉為 {@link List} &lt;{@link String}&gt;。
     *
     * @param filePath 要讀取的檔案路徑
     * @return 檔案每一列所組成的文字清單
     * @throws java.io.IOException 當讀取失敗時拋出
     */
    public static List<String> fileToStringArrayList(String filePath) throws IOException {
        byte[] bytes = fileToByteArray(filePath);
        List<String> listFileString = TypeConvert.byteToStringArrayList(bytes);
        return listFileString;

    }


    // ====================== 檔案檢查相關 ======================

    /**
     * 舊方法的 InputStream 版本,方便在記憶體或資源流上直接測試。
     *
     * @param input 要測試的 InputStream(呼叫方需負責關閉或傳入可重複使用的流)
     * @return 若能成功以 Properties 載入則回傳 {@code true},否則回傳 {@code false}
     * @throws IOException IOException 當讀取流時發生 IO 錯誤會拋出(呼叫端可自行處理)
     */
    public static boolean isPropertiesFile(InputStream input) throws IOException {
        Properties properties = new Properties();
        properties.load(input);
        return true;
    }

    /**
     * 檢查指定路徑是否存在檔案或目錄。
     *
     * @param filePath 檔案或目錄路徑
     * @return 若存在則回傳 {@code true},否則 {@code false}
     */
    public static Boolean checkFileExist(String filePath) {
        File file = new File(filePath);
        return (file.exists() || file.isDirectory());
    }

    /**
     * 刪除指定檔案或路徑。
     *
     * @param filePath 要刪除的檔案或目錄路徑
     * @return 刪除成功回傳 {@code true},否則回傳 {@code false}
     */
    public static boolean deleteFile(String filePath) {
        Path delFilePath = Paths.get(filePath);
        try {
            Files.delete(delFilePath);
            log.info("File deleted successfully: {}", filePath);
            return true;
        } catch (NoSuchFileException e) {
            log.error("Error: File not found - {}", filePath);
        } catch (DirectoryNotEmptyException e) {
            log.error("Error: Directory is not empty - {} ", filePath);
        } catch (IOException e) {
            log.error("Error deleting file {} : {} ", filePath, e.getMessage());
        }
        return false;
    }

    /**
     * 產生唯一檔名(含預設路徑)。
     *組成格式: {@code GlobalConstants.DEFAULT_FOLDER_PATH + fileName + _ + yyyyMMddHHmmss + UUID} 
     *
     * @param fileName 檔名前綴
     * @return 產生的絕對檔案路徑(字串)
     */
    public static String getUniqFileName(String fileName) {
        String uuidString = UUID.randomUUID().toString();
        while (uuidString.contains("-")) {
            uuidString = uuidString.replace("-", "");
        }
        String filePath = GlobalConstants.DEFAULT_FOLDER_PATH + fileName + "_"
                + DateUtils.dateTimeNowString(DateUtils.YYYYMMDDHHMMSS) + uuidString;
        return filePath;
    }

    // ===================== 檔名處理相關 ======================
    /**
     * 從完整路徑中取得檔名(不含目錄路徑)。
     *
     * @param filePath 完整檔案路徑
     * @return 只包含檔名的字串,若輸入為空或 null 回傳 null
     */
    public static String getName(String filePath) {
        if (StringUtils.isBlank(filePath)) {
            return null;
        }
        int lastUnixPos = filePath.lastIndexOf('/');
        int lastWindowsPos = filePath.lastIndexOf('\\');
        int index = Math.max(lastUnixPos, lastWindowsPos);
        return filePath.substring(index + 1);
    }

    /**
     * 取得檔名的基底(去除第一個 '.' 之後的所有副檔名部分)。
     *
     * @param fileName 原始檔名
     * @return 基底檔名,若輸入為空則回傳 null
     */
    public static String getFileNameBase(String fileName) {
        if (StringUtils.isBlank(fileName)) {
            return null;
        }
        List<String> splitString = CommUtils.splitDelimiter(fileName, ".");
        String baseName = splitString.get(0);
        return baseName;
    }

    /**
     * 去除最後一個副檔名(包含 '.')前的所有內容之外,保留中間的 '.'(若存在多重副檔名則保留中間部分)。
     *
     * @param fileName 原始檔名
     * @return 去除最末端副檔名的檔名,若輸入為空則回傳 null
     */
    public static String getFileNameNotSuffix(String fileName) {
        if (StringUtils.isBlank(fileName)) {
            return null;
        }
        List<String> splitString = CommUtils.splitDelimiter(fileName, ".");
        if (splitString.isEmpty()) {
            return fileName;
        }
        StringBuilder stringBuilder = new StringBuilder(splitString.get(0));
        for (int i = 1; i < splitString.size() - 1; i++) {
            stringBuilder.append(".").append(splitString.get(i));
        }
        return stringBuilder.toString();
    }

    // ===================== 尋找檔案相關 ======================

    /**
     * 在 classpath 內尋找指定檔案的絕對路徑(prefix 為空時從專案 root 開始搜尋)。
     *
     * @param fileName 欲查找的檔案名稱
     * @return 找到的檔案絕對路徑,若找不到回傳 null
     * @throws IOException IOException 資源存取或解析失敗時拋出
     */
    public static String getFileAbsolutePathInClass(String fileName) throws IOException {
        return getFileAbsolutePath("", fileName);
    }

    /**
    * 在 classpath 中尋找符合 preFix + '**' + '/' + fileName 模式的資源,並回傳第一個符合項目的絕對路徑。
     *
    * @param preFix   搜尋前綴(可為資料夾路徑),最後會以 glob-like 模式於 classpath 中搜尋(例如 '**' + '/' + fileName)
     * @param fileName 檔案名稱
     * @return 若找到則回傳該資源的絕對路徑,找不到則回傳 null
     * @throws IOException IOException 資源解析或讀取失敗時拋出
     */
    public static String getFileAbsolutePath(String preFix, String fileName) throws IOException {
        PathMatchingResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        Resource[] resources = resourcePatternResolver.getResources("classpath*:" + preFix + "**/" + fileName);
        String foundFilePath = null;
        for (Resource resource : resources) {
            File file = resource.getFile();
            foundFilePath = file.getAbsolutePath();
            if (foundFilePath.concat(fileName) != null) {
                break;
            }
        }
        return foundFilePath;
    }

    /**
     * 遞迴搜尋指定資料夾下的檔案清單,支援以副檔名過濾(包含通配符 "*" 或空字串表示不過濾)。
     *
     * @param folderPath    要搜尋的起始資料夾路徑
     * @param fileExtension 副檔名過濾條件(例如 ".txt" 或 "txt"),若為空或 "*" 則回傳所有檔案
     * @return 所有符合條件的檔案絕對路徑清單
     * @throws IOException IOException 當檔案系統存取失敗時拋出
     */
    public static List<String> getFiles(String folderPath, String fileExtension) throws IOException {

        List<String> listFile = new ArrayList<>();

        try {
            Files.walkFileTree(Paths.get(folderPath), new FileVisitor<Path>() {
                @Override
                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    String filePath = file.toString();
                    if (StringUtils.isBlank(fileExtension) || fileExtension.equals("*")) {
                        listFile.add(filePath);
                        return FileVisitResult.CONTINUE;
                    } else {
                        if (filePath.endsWith(fileExtension)) {
                            listFile.add(filePath);
                        }
                    }

                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                    return FileVisitResult.CONTINUE;
                }
            });
        } catch (IOException e) {
             log.error("檔案操作失敗: {}", e.getMessage());
             throw e;
        }

        return listFile;
    }

    // ===================== 檔案格式判斷相關 ======================

    /**
     * 根據檔案內容判斷圖片格式(副檔名),支援 GIF / JPG / BMP / PNG 等常見格式。
     *此方法透過檢查檔案前方的 magic bytes(檔頭)來判斷格式,非透過副檔名判斷,較為可靠。 
     *
     * @param photoByte 圖檔的位元組陣列(至少應包含前 10 個位元以進行判斷)
     * @return 判斷出的圖片格式副檔名(例如 "jpg", "png", "gif", "bmp"),若無法判斷預設回傳 "jpg"
     */
    public static String getFileExtendName(byte[] photoByte) {
        String strFileExtendName = "jpg";
        if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56)
                && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97)) {
            strFileExtendName = "gif";
        } else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70)) {
            strFileExtendName = "jpg";
        } else if ((photoByte[0] == 66) && (photoByte[1] == 77)) {
            strFileExtendName = "bmp";
        } else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71)) {
            strFileExtendName = "png";
        }
        return strFileExtendName;
    }
}

單元測試程式碼 FileUtilsTest.java

package tw.lewishome.webapp.base.utility.common;

import org.junit.jupiter.api.*;

import tw.lewishome.webapp.GlobalConstants;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.*;
import static org.junit.jupiter.api.Assertions.*;

class FileUtilsTest {

    private File tempFile;
    private String tempFilePath;

    /**
     * @throws IOException IOException
     */
    @BeforeEach
    void setUp() throws IOException {
        tempFile = File.createTempFile("testFileUtils", ".txt");
        tempFilePath = tempFile.getAbsolutePath();
        Files.write(tempFile.toPath(), Arrays.asList("line1", "line2", "line3"), StandardCharsets.UTF_8);
    }

    @AfterEach
    void tearDown() {
        if (tempFile != null && tempFile.exists()) {
            tempFile.delete();
        }
    }

    @Test
    void testGetName() {
        assertEquals("file.txt", FileUtils.getName("/path/to/file.txt"));
        assertEquals("file.txt", FileUtils.getName("C:\\path\\to\\file.txt"));
        assertNull(FileUtils.getName(null));
    }

    @Test
    void testGetFileNameNotSuffix() {
        assertEquals("file", FileUtils.getFileNameNotSuffix("file.txt"));
        assertEquals("archive.tar", FileUtils.getFileNameNotSuffix("archive.tar.gz"));
        assertNull(FileUtils.getFileNameNotSuffix(null));
    }

    @Test
    void testGetFileNameBase() {
        assertEquals("file", FileUtils.getFileNameBase("file.txt"));
        assertEquals("archive", FileUtils.getFileNameBase("archive.tar.gz"));
        assertNull(FileUtils.getFileNameBase(null));
    }

    /**
     * @throws IOException IOException
     */
    @Test
    void testFileToByteArrayAndBack() throws IOException {
        byte[] bytes = FileUtils.fileToByteArray(tempFilePath);
        assertNotNull(bytes);
        File tempOut = File.createTempFile("testFileUtilsOut", ".txt");
        String outPath = tempOut.getAbsolutePath();
        FileUtils.byteArrayToFile(bytes, outPath);
        assertTrue(new File(outPath).exists());
        tempOut.delete();
    }

    /**
     * @throws IOException IOException
     */
    @Test
    void testStringArrayListToFileAndBack() throws IOException {

        List<String> lines = Arrays.asList("line1", "line2", "line3");
        FileUtils.stringArrayListToFile(lines, tempFilePath);
        List<String> readLines = FileUtils.fileToStringArrayList(tempFilePath);
        assertEquals(lines, readLines);
    }

    @Test
    void testCheckFileExist() {
        assertTrue(FileUtils.checkFileExist(tempFilePath));
        assertFalse(FileUtils.checkFileExist("nonexistent_file.txt"));
    }

    /**
     * @throws IOException IOException
     */
    @Test
    void testDeleteFile() throws IOException {
        File temp = File.createTempFile("testDelete", ".txt");
        String path = temp.getAbsolutePath();
        assertTrue(temp.exists());
        assertTrue(FileUtils.deleteFile(path));
        assertFalse(new File(path).exists());
    }

    @Test
    void testGetFileExtendName() {
        // GIF header: 47 49 46 38 39 61
        byte[] gif = { 71, 73, 70, 56, 57, 97, 0, 0, 0, 0 };
        assertEquals("gif", FileUtils.getFileExtendName(gif));
        // JPG header: 0xFF 0xD8 ... 0x4A 0x46 0x49 0x46
        byte[] jpg = { 0, 0, 0, 0, 0, 0, 74, 70, 73, 70 };
        assertEquals("jpg", FileUtils.getFileExtendName(jpg));
        // BMP header: 66 77
        byte[] bmp = { 66, 77, 0, 0, 0, 0, 0, 0, 0, 0 };
        assertEquals("bmp", FileUtils.getFileExtendName(bmp));
        // PNG header: 0 80 78 71
        byte[] png = { 0, 80, 78, 71, 0, 0, 0, 0, 0, 0 };
        assertEquals("png", FileUtils.getFileExtendName(png));
        // Default
        byte[] unknown = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        assertEquals("jpg", FileUtils.getFileExtendName(unknown));
    }

    @Test
    void testGetUniqFileName() {

        String fileName = FileUtils.getUniqFileName("test");
        System.out.println("Generated file name: " + fileName);
        String prefixFileName = GlobalConstants.DEFAULT_FOLDER_PATH + "test_20240101120000";
        int fileNameLength = (prefixFileName.length() + 32);
        assertEquals(fileName.length(), fileNameLength);
    }

    /**
     * @throws IOException IOException
     */
    @Test
    void testStreamToFile() throws IOException {
        // Write to temp file
        byte[] data = "hello world".getBytes(StandardCharsets.UTF_8);
        Files.write(tempFile.toPath(), data);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        FileUtils.streamToFile(byteArrayOutputStream, tempFilePath);
        assertArrayEquals(data, byteArrayOutputStream.toByteArray());
    }

    @Test
    void testGetFileAbsolutePathInClassAndGetFileAbsolutePath() throws IOException {
        // These methods depend on Spring's PathMatchingResourcePatternResolver and
        // actual resources on classpath.
        // For unit test, just check that it returns null for non-existing file.
        assertNull(FileUtils.getFileAbsolutePathInClass("nonexistent.file"));
        assertNull(FileUtils.getFileAbsolutePath("prefix/", "nonexistent.file"));
    }

    @Test
    void testGetFileThrowsException() {
        assertThrows(Exception.class, () -> FileUtils.fileToInputStream("nonexistent.file"));
    }

    @Test
    void testGetFilesWithExtension() throws IOException {
        File tempDir = Files.createTempDirectory("testGetFiles").toFile();
        try {
            File jarFile1 = new File(tempDir, "file1.jar");
            File jarFile2 = new File(tempDir, "file2.jar");
            File txtFile = new File(tempDir, "file.txt");
            jarFile1.createNewFile();
            jarFile2.createNewFile();
            txtFile.createNewFile();

            List<String> jarFiles = FileUtils.getFiles(tempDir.getAbsolutePath(), "jar");
            assertEquals(2, jarFiles.size());
            assertTrue(jarFiles.stream().anyMatch(f -> f.endsWith("file1.jar")));
            assertTrue(jarFiles.stream().anyMatch(f -> f.endsWith("file2.jar")));
        } finally {
            for (File f : Objects.requireNonNull(tempDir.listFiles())) {
                f.delete();
            }
            tempDir.delete();
        }
    }

    @Test
    void testGetFilesWithNoExtension() throws IOException {
        File tempDir = Files.createTempDirectory("testGetFilesNoExt").toFile();
        try {
            File file1 = new File(tempDir, "file1");
            File file2 = new File(tempDir, "file2");
            File txtFile = new File(tempDir, "file.txt");
            file1.createNewFile();
            file2.createNewFile();
            txtFile.createNewFile();

            List<String> noExtFiles = FileUtils.getFiles(tempDir.getAbsolutePath(), "");
            assertEquals(3, noExtFiles.size());
            assertTrue(noExtFiles.stream().anyMatch(f -> f.endsWith("file1")));
            assertTrue(noExtFiles.stream().anyMatch(f -> f.endsWith("file2")));
            assertTrue(noExtFiles.stream().anyMatch(f -> f.endsWith("file.txt")));
        } finally {
            for (File f : Objects.requireNonNull(tempDir.listFiles())) {
                f.delete();
            }
            tempDir.delete();
        }
    }

    @Test
    void testGetAllSubFolderFilesWithExtension() {
        File tempDir = null;
        try {
            tempDir = Files.createTempDirectory("testGetFilesAllSub").toFile();
            File subDir = new File(tempDir, "subdir");
            subDir.mkdir();
            File jarFile1 = new File(tempDir, "file1.jar");
            File jarFile2 = new File(subDir, "file2.jar");
            File txtFile = new File(subDir, "file.txt");
            jarFile1.createNewFile();
            jarFile2.createNewFile();
            txtFile.createNewFile();

            List<String> jarFiles = FileUtils.getFiles(tempDir.getAbsolutePath(), "jar");
            assertEquals(2, jarFiles.size());
            assertTrue(jarFiles.stream().anyMatch(f -> f.endsWith("file1.jar")));
            assertTrue(jarFiles.stream().anyMatch(f -> f.endsWith("file2.jar")));
        } catch (IOException e) {
            fail("IOException during test setup: " + e.getMessage());
        } finally {
            if (tempDir != null) {
                for (File f : Objects.requireNonNull(tempDir.listFiles())) {
                    if (f.isDirectory()) {
                        for (File subF : Objects.requireNonNull(f.listFiles())) {
                            subF.delete();
                        }
                    }
                    f.delete();
                }
                tempDir.delete();
            }
        }

    }

    @Test
    void testGetAllSubFolderFilesWithNoExtension() {
        File tempDir = null;
        try {
            tempDir = Files.createTempDirectory("testGetFilesAllSubNoExt").toFile();
            File subDir = new File(tempDir, "subdir");
            subDir.mkdir();
            File file1 = new File(tempDir, "file1");
            File file2 = new File(subDir, "file2");
            File txtFile = new File(subDir, "file.txt");
            file1.createNewFile();
            file2.createNewFile();
            txtFile.createNewFile();

            List<String> noExtFiles = FileUtils.getFiles(tempDir.getAbsolutePath(), "");
            assertEquals(3, noExtFiles.size());
            assertTrue(noExtFiles.stream().anyMatch(f -> f.endsWith("file1")));
            assertTrue(noExtFiles.stream().anyMatch(f -> f.endsWith("file2")));
            assertTrue(noExtFiles.stream().anyMatch(f -> f.endsWith("file.txt")));
        } catch (IOException e) {
            fail("IOException during test setup: " + e.getMessage());
        } finally {
            if (tempDir != null) {
                for (File f : Objects.requireNonNull(tempDir.listFiles())) {
                    if (f.isDirectory()) {
                        for (File subF : Objects.requireNonNull(f.listFiles())) {
                            subF.delete();
                        }
                    }
                    f.delete();
                }
                tempDir.delete();
            }
        }
    }

    @Test
    void testByteArrayToFileTempAndCleanup() throws IOException {
        // ensure default folder exists
        File defaultFolder = new File(GlobalConstants.DEFAULT_FOLDER_PATH);
        if (!defaultFolder.exists()) {
            defaultFolder.mkdirs();
        }
        byte[] data = "temp data".getBytes(StandardCharsets.UTF_8);
        String path = FileUtils.byteArrayToFileTemp(data);
        assertNotNull(path);
        File created = new File(path);
        assertTrue(created.exists());
        // cleanup
        created.delete();
    }

    @Test
    void testDeleteNonexistentFileReturnsFalse() {
        String fakePath = System.getProperty("java.io.tmpdir") + "/nonexistent_file_12345.tmp";
        // ensure it's not there
        File f = new File(fakePath);
        if (f.exists()) {
            f.delete();
        }
        assertFalse(FileUtils.deleteFile(fakePath));
    }

    @Test
    void testCheckFileExistForDirectory() throws IOException {
        File tempDir = Files.createTempDirectory("testDirExist").toFile();
        try {
            assertTrue(FileUtils.checkFileExist(tempDir.getAbsolutePath()));
        } finally {
            tempDir.delete();
        }
    }
}

圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言