Java判断文件类型的方式:通过后缀名,通过获取文件的Content-type判断,通过头文件字节数据判断文件类型

  Bob

    1. 通过后缀名

    2. Web项目可通过获取文件的Content-type判断

    3. 通过头文件字节数据判断文件类型

    给出通过头文件字节数据判断文件类型Java实现

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Map.Entry;
    
    /**
     *  类描述:根据字节数据判断文件类型
     * 
     *  @author:  bob
     *  @version  1.0
     *
     *  History:  2018年6月7日 下午2:23:34   bob   Created.
     *           
     */
    public class FileTypeUtil {
        
        private final static Map<String, String> FILE_TYPE_MAP = new HashMap<String, String>();    
        
        private FileTypeUtil(){}    
        static{    
            getAllFileType(); 
        }    
            
        /**  
         * 文件头信息,待补充
         */    
        private static void getAllFileType()    
        {
            FILE_TYPE_MAP.put("zip", "504B0304");
            FILE_TYPE_MAP.put("rar", "52617221");   
            FILE_TYPE_MAP.put("jpg", "FFD8FF"); //JPEG (jpg)    
            FILE_TYPE_MAP.put("png", "89504E47");  //PNG (png)    
            FILE_TYPE_MAP.put("gif", "47494638");  //GIF (gif)    
            FILE_TYPE_MAP.put("tif", "49492A00");  //TIFF (tif)    
            FILE_TYPE_MAP.put("bmp", "424D"); //Windows Bitmap (bmp)    
            FILE_TYPE_MAP.put("dwg", "41433130"); //CAD (dwg)    
            FILE_TYPE_MAP.put("html", "68746D6C3E");  //HTML (html)    
            FILE_TYPE_MAP.put("rtf", "7B5C727466");  //Rich Text Format (rtf)    
            FILE_TYPE_MAP.put("xml", "3C3F786D6C");    
             
            FILE_TYPE_MAP.put("PSD", "38425053");  //photoshop (psd)    
            FILE_TYPE_MAP.put("eml", "44656C69766572792D646174653A");  //Email [thorough only] (eml)    
            
            FILE_TYPE_MAP.put("xlsx.docx", "504B030414000600080000002100");
            
            FILE_TYPE_MAP.put("dbx", "CFAD12FEC5FD746F");  //Outlook Express (dbx)    
            FILE_TYPE_MAP.put("pst", "2142444E");  //Outlook (pst)    
            FILE_TYPE_MAP.put("xls.doc", "D0CF11E0");  //MS Word    注意:word 和 excel的文件头一样    
            
            FILE_TYPE_MAP.put("mdb", "5374616E64617264204A");  //MS access (mdb)    
            FILE_TYPE_MAP.put("wpd", "FF575043"); //WordPerfect (wpd)     
            FILE_TYPE_MAP.put("eps", "252150532D41646F6265");    
            FILE_TYPE_MAP.put("ps", "252150532D41646F6265");    
            FILE_TYPE_MAP.put("pdf", "255044462D312E");  //Adobe Acrobat (pdf)    
            FILE_TYPE_MAP.put("qdf", "AC9EBD8F");  //Quicken (qdf)    
            FILE_TYPE_MAP.put("pwl", "E3828596");  //Windows Password (pwl)    
            FILE_TYPE_MAP.put("wav", "57415645");  //Wave (wav)    
            FILE_TYPE_MAP.put("avi", "41564920");    
            FILE_TYPE_MAP.put("ram", "2E7261FD");  //Real Audio (ram)    
            FILE_TYPE_MAP.put("rm", "2E524D46");  //Real Media (rm)    
            FILE_TYPE_MAP.put("mpg", "000001BA");  //    
            FILE_TYPE_MAP.put("mov", "6D6F6F76");  //Quicktime (mov)    
            FILE_TYPE_MAP.put("asf", "3026B2758E66CF11"); //Windows Media (asf)    
            FILE_TYPE_MAP.put("mid", "4D546864");  //MIDI (mid)    
        }
        
        /**  
         * 获取文件类型,包括图片,若格式不是已配置的,则返回null
         */    
        public final static String getFileByFile(File file)
        {
            String filetype = null;    
            byte[] b = new byte[50];    
            try    
            {
                InputStream is = new FileInputStream(file);    
                is.read(b);    
                filetype = getFileTypeByStream(b);    
                is.close();    
            }    
            catch (FileNotFoundException e)    
            {    
                e.printStackTrace();    
            }    
            catch (IOException e)    
            {    
                e.printStackTrace();    
            }    
            return filetype;    
        }    
            
        public final static String getFileTypeByStream(byte[] b)    
        {    
            String filetypeHex = String.valueOf(getFileHexString(b));    
            Iterator<Entry<String, String>> entryiterator = FILE_TYPE_MAP.entrySet().iterator();    
            while (entryiterator.hasNext()) {    
                Entry<String,String> entry =  entryiterator.next();    
                String fileTypeHexValue = entry.getValue();    
                if (filetypeHex.toUpperCase().startsWith(fileTypeHexValue)) {
                    return entry.getKey();    
                }    
            }    
            return null;    
        }    
    
          
        private final static String getFileHexString(byte[] b)    
        {    
            StringBuilder stringBuilder = new StringBuilder();    
            if (b == null || b.length <= 0)    
            {    
                return null;    
            }    
            for (int i = 0; i < b.length; i++)    
            {    
                int v = b[i] & 0xFF;    
                String hv = Integer.toHexString(v);    
                if (hv.length() < 2)    
                {    
                    stringBuilder.append(0);    
                }    
                stringBuilder.append(hv);    
            }    
            return stringBuilder.toString();    
        }
    
    }

    然而,在安全性较高的业务场景中,1,2两种方法的校验会被轻易绕过。

    1. 伪造后缀名,非常容易修改

    2. 伪造文件的Content-type,这个稍微复杂点

    3. 较安全,但是要读取文件,并有16进制转换等操作,性能稍差,但能满足一定条件下对安全的要求,所以建议使用,但是文件头的信息也可以伪造。




    如有疑问或同行交流欢迎加群讨论:铂金信息技术交流群 151258054