SpringBoot 获取上传文件真实格式

一、如何获取真实文件格式?
当把文件的二进制数据转换成十六进制时,同类型文件的文件头数据是相同的,即使改变了其后缀,这个数据也不会改变。文件头是位于文件开头的一段承担一定任务的数据,一般在开头部分。头文件作为一种包含功能函数、数据接口声明的载体文件,用于保存程序声明(declaration),而定义文件用于保存程序的实现(implementation)。一般文件头开始几节数据是固定的,被称为魔数,作为区分文件类型的硬添加进去的数据。(例如PNG格式的十六进制文件头数据就是以"89504E47"开头的,就可以判定该文件是PNG格式)为了解决在用户上传文件的时候在服务器端判断文件类型的问题,故用获取文件头的方式,直接读取文件的前几个字节,来判断文件的真实类型。
————————————————

  1. 自定义魔数文件类型(可根据产品经理提供的业务格式进行定义)
 public enum FileType {

    /**
     * JEPG.
     */
    JPEG("FFD8FF"),

    /**
     * PNG.
     */
    PNG("89504E47"),

    /**
     * GIF.
     */
    GIF("47494638"),

    /**
     * TIFF.
     */
    TIFF("49492A00"),

    TXT("6C657420"),

    /**
     * Windows Bitmap.
     */
    BMP("424D"),

    /**
     * CAD.
     */
    DWG("41433130"),

    /**
     * Adobe Photoshop.
     */
    PSD("38425053"),

    /**
     * Rich Text Format.
     */
    RTF("7B5C727466"),

    /**
     * XML.
     */
    XML("3C3F786D6C"),

    /**
     * HTML.
     */
    HTML("68746D6C3E"),

    /**
     * Email.
     */
    EML("44656C69766572792D646174653A"),

    /**
     * Outlook Express.
     */
    DBX("CFAD12FEC5FD746F"),

    /**
     * Outlook (pst).
     */
    PST("2142444E"),

    /**
     * MS Word/Excel.
     */
    XLS_DOC("D0CF11E0"),

    /**
     * MS Access.
     */
    MDB("5374616E64617264204A"),

    /**
     * WordPerfect.
     */
    WPD("FF575043"),

    /**
     * Postscript.
     */
    EPS("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).
     */
    MPG("000001BA"),

    /**
     * Quicktime.
     */
    MOV("6D6F6F76"),

    /**
     * Windows Media.
     */
    ASF("3026B2758E66CF11"),

    GZ("1F8B08"),
    /**
     * MIDI.
     */
    MID("4D546864");

    private String value = "";


    /**
     * Constructor.
     *
     * @param value
     */
    private FileType(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}
  1. FileUtil
@Service
public class FileUtil {

    /**
     * @param inputStream
     * @throws IOException
     * @description 第一步:获取文件输入流
     */
    private static String getFileContent(InputStream inputStream) throws IOException {
        byte[] b = new byte[20];
        try {
            inputStream.read(b, 0, 20);
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    throw e;
                }
            }
        }
        return bytesToHexString(b);
    }

    /**
     * @param
     * @return 16进制字符串
     * @description 第二步:将文件头转换成16进制字符串
     */
    private static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * @param inputStream
     * @return 文件类型
     * @description 第三步:根据十六进制字符串判断文件类型格式
     */
    public FileType getType(InputStream inputStream) throws IOException {
        String fileHead = getFileContent(inputStream);
        if (fileHead == null || fileHead.length() == 0) {
            return null;
        }
        fileHead = fileHead.toUpperCase();
        FileType[] fileTypes = FileType.values();
        for (FileType type : fileTypes) {
//         startsWith() 方法用于检测字符串是否以指定的前缀开始
            if (fileHead.startsWith(type.getValue())) {
                return type;
            }
        }
        return null;
    }

}
  1. upload (在上传业务体系中调用获取类型)

String fileFormat = fileUtil.getType(typeIs).name();

   String suffixName = null;
    //获取类型流
    final InputStream typeIs = file.getInputStream();
    String fileOrgName = file.getOriginalFilename();
    String fileFormat = fileUtil.getType(typeIs).name();
    if (StringUtils.isEmpty(fileFormat)) {
        suffixName = fileOrgName.substring(fileOrgName.lastIndexOf("."));
    } else {
        //获取魔数类型
        suffixName = "." + fileFormat.toLowerCase();
    }
    String uid = minioTemplate.randomUUID();
    String fileName = uid + suffixName;

实测有效 非常好用

上一篇:单例模式的饿汉式读取db.properties文件中的内容


下一篇:Android 学习笔记(8)之JavaIO原理