Java依據文件頭獲取文件類型

簡介

文件頭是位於文件開頭的一段承擔一定任務的數據,一般都在開頭的部分。頭文件作爲一種包含功能函數、數據接口聲明的載體文件,用於保存程序的聲明(declaration),而定義文件用於保存程序的實現 (implementation)。

爲了解決在用戶上傳文件的時候在服務器端判斷文件類型的問題,故用獲取文件頭的方式,直接讀取文件的前幾個字節,來判斷上傳文件是否符合格式。

問題

現有一文件,其擴展名未知或標記錯誤。假設它是一個正常的、非空的文件,且將擴展名更正後可以正常使用,那麼,如何判斷它是哪種類型的文件?

在後綴未知,或者後綴被修改的文件,依然通過文件頭來判斷該文件究竟是什麼文件類型。我們可以使用一個文本編輯工具如 UltraEditUniversalViewer 打開文件(16進制模式下),然後看文件頭是什麼字符,以下是常見文件類型的文件頭字符(16進制),希望對你有幫助:

文件 文件頭
JPEG (jpg) FFD8FF
PNG (png) 89504E47
GIF (gif) 47494638
TIFF (tif) 49492A00
Windows Bitmap (bmp) 424D
CAD (dwg) 41433130
Adobe Photoshop (psd) 38425053
Rich Text Format (rtf) 7B5C727466
XML (xml) 3C3F786D6C
HTML (html) 68746D6C3E
Email [thorough only] (eml) 44656C69766572792D646174653A
Outlook Express (dbx) CFAD12FEC5FD746F
Outlook (pst) 2142444E
MS Word/Excel (xls.or.doc) D0CF11E0
MS Access (mdb) 5374616E64617264204A
WordPerfect (wpd) FF575043
Postscript (eps.or.ps) 252150532D41646F6265
Adobe Acrobat (pdf) 255044462D312E
Quicken (qdf) AC9EBD8F
Windows Password (pwl) E3828596
ZIP Archive (zip) 504B0304
RAR Archive (rar) 52617221
Wave (wav) 57415645
AVI (avi) 41564920
Real Audio (ram) 2E7261FD
Real Media (rm) 2E524D46
MPEG (mpg) 000001BA
MPEG (mpg) 000001B3
Quicktime (mov) 6D6F6F76
Windows Media (asf) 3026B2758E66CF11
MIDI (mid) 4D546864

源碼

package com.blog.www.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 文件類型
 * <br/>
 *
 * @author :leigq
 * @date :2019/7/30 10:07
 */
public class FileTypes {

	private static final Map<FileTypeName, String> FILE_TYPE_MAP = new HashMap<>();

	static {
		// 初始化文件類型信息
		initAllFileType();
	}

	private FileTypes() {
	}

	/**
	 * 文件類型名稱枚舉
	 * <br/>
	 *
	 * @author :leigq
	 * @date :2019/7/30 10:20
	 */
	public enum FileTypeName {

		JPG("jpg"),

		PNG("png"),

		GIF("gif"),

		// ....根據自己需要添加更多
		;

		private String fileTypeName;

		FileTypeName(String fileTypeName) {
			this.fileTypeName = fileTypeName;
		}

		@Override
		public String toString() {
			return fileTypeName;
		}
	}

	/**
	 * 驗證文件類型
	 * <br/>
	 * create by: leigq
	 * <br/>
	 * create time: 2019/7/30 10:25
	 *
	 * @param fileTypeName 文件類型名稱枚舉
	 * @param file         文件
	 * @return if 文件類型 = 文件類型名稱枚舉 return true , else return false
	 */
	public static Boolean checkType(FileTypeName fileTypeName, File file) {
		try {
			FileInputStream fileInputStream = new FileInputStream(file);
			byte[] b = new byte[10];
			// 讀取文件前10個字節
			int read = fileInputStream.read(b, 0, b.length);
			if (read != -1) {
				// 將字節轉換爲16進制字符串
				String fileCode = bytesToHexString(b).toUpperCase();
				// 獲取對應文件類型的文件頭
				String fileTypeHead = FILE_TYPE_MAP.get(fileTypeName);
				return fileCode.startsWith(fileTypeHead) || fileTypeHead.startsWith(fileCode);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}


	/**
	 * 獲取文件類型
	 *
	 * @param file 文件
	 * @return 文件類型,if 獲取不到類型 return "-1"
	 */
	public static String getType(File file) {
		try {
			FileInputStream is = new FileInputStream(file);
			byte[] b = new byte[10];
			int read = is.read(b, 0, b.length);
			if (read != -1) {
				String fileCode = bytesToHexString(b).toUpperCase();
				for (Map.Entry<FileTypeName, String> next : FILE_TYPE_MAP.entrySet()) {
					String fileTypeHead = next.getValue();
					if (fileTypeHead.startsWith(fileCode) || fileCode.startsWith(fileTypeHead)) {
						return next.getKey().toString();
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return "-1";
	}

	/**
	 * 初始化常見文件頭信息
	 * <br/>
	 * create by: leigq
	 * <br/>
	 * create time: 2019/7/30 10:19
	 */
	private static void initAllFileType() {
		// JPEG (jpg)
		FILE_TYPE_MAP.put(FileTypeName.JPG, "FFD8FF");

		// PNG (png)
		FILE_TYPE_MAP.put(FileTypeName.PNG, "89504E47");

		// GIF (gif)
		FILE_TYPE_MAP.put(FileTypeName.GIF, "47494638");

		// ....根據自己需要添加更多, 文件頭編碼請用大寫
	}

	/**
	 * 將字節數組轉換成16進制字符串
	 *
	 * @param bytes 待轉換字節數組
	 */
	private static String bytesToHexString(byte[] bytes) {
		StringBuilder stringBuilder = new StringBuilder();
		for (byte b : bytes) {
			int v = b & 0xFF;
			String hv = Integer.toHexString(v);
			if (hv.length() < 2) {
				stringBuilder.append(0);
			}
			stringBuilder.append(hv);
		}
		return stringBuilder.toString();
	}

}

測試

/**
 * 測試
 * <br/>
 * create by: leigq
 * <br/>
 * create time: 2019/7/30 11:32
 */
public static void main(String[] args) {
    // 驗證 PNG
    File pngImg = new File("C:\\file_type\\png_test.png");
    System.out.println(checkType(FileTypeName.PNG, pngImg));
    System.out.println(getType(pngImg));

    System.out.println("------------------");

    // 驗證 JPG
    File jpgImg = new File("C:\\file_type\\jpg_test.jpg");
    System.out.println(checkType(FileTypeName.JPG, jpgImg));
    System.out.println(getType(jpgImg));

    System.out.println("------------------");

    // 驗證 GIF
    File gifImg = new File("C:\\file_type\\gif_test.gif");
    System.out.println(checkType(FileTypeName.GIF, gifImg));
    System.out.println(getType(gifImg));

    System.out.println("------------------");

    // 驗證 未知類型文件
    File unknown = new File("C:\\file_type\\123.md");
    System.out.println(checkType(FileTypeName.GIF, unknown));
    System.out.println(getType(unknown));
}

在這裏插入圖片描述

參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章