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));
}

在这里插入图片描述

参考


作者:不敲代码的攻城狮
出处:https://www.cnblogs.com/leigq/
任何傻瓜都能写出计算机可以理解的代码。好的程序员能写出人能读懂的代码。

 
原文地址:https://www.cnblogs.com/leigq/p/13406540.html