java根据文件头判断文件格式

本文介绍了一个用于识别文件类型的Java工具类。该工具通过读取文件头部的特定字节序列来判断文件格式,支持多种常见文件类型,如图片、文档、音频、视频等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

public class FileTypeUtil {

    private final static Map<String, String> FILE_TYPE_MAP = new HashMap<String, String>();  
    private static Logger log = LoggerFactory.getLogger(FileTypeUtil.class);
    private FileTypeUtil(){}  
      
    static{  
        getAllFileType();  //初始化文件类型信息  
    }  
          
    private static void getAllFileType(){  
        FILE_TYPE_MAP.put("ffd8ffe000104a464946", "jpg"); //JPEG (jpg)     
        FILE_TYPE_MAP.put("89504e470d0a1a0a0000", "png"); //PNG (png)     
        FILE_TYPE_MAP.put("47494638396126026f01", "gif"); //GIF (gif)     
        FILE_TYPE_MAP.put("49492a00227105008037", "tif"); //TIFF (tif)     
        FILE_TYPE_MAP.put("424d228c010000000000", "bmp"); //16色位图(bmp)     
        FILE_TYPE_MAP.put("424d8240090000000000", "bmp"); //24位位图(bmp)     
        FILE_TYPE_MAP.put("424d8e1b030000000000", "bmp"); //256色位图(bmp)     
        FILE_TYPE_MAP.put("41433130313500000000", "dwg"); //CAD (dwg)     
        FILE_TYPE_MAP.put("3c21444f435459504520", "html"); //HTML (html)
        FILE_TYPE_MAP.put("3c21646f637479706520", "htm"); //HTM (htm)
        FILE_TYPE_MAP.put("48544d4c207b0d0a0942", "css"); //css
        FILE_TYPE_MAP.put("696b2e71623d696b2e71", "js"); //js
        FILE_TYPE_MAP.put("7b5c727466315c616e73", "rtf"); //Rich Text Format (rtf)     
        FILE_TYPE_MAP.put("38425053000100000000", "psd"); //Photoshop (psd)     
        FILE_TYPE_MAP.put("46726f6d3a203d3f6762", "eml"); //Email [Outlook Express 6] (eml)       
        FILE_TYPE_MAP.put("d0cf11e0a1b11ae10000", "doc"); //MS Excel 注意:word、msi 和 excel的文件头一样     
        FILE_TYPE_MAP.put("d0cf11e0a1b11ae10000", "vsd"); //Visio 绘图     
        FILE_TYPE_MAP.put("5374616E64617264204A", "mdb"); //MS Access (mdb)      
        FILE_TYPE_MAP.put("252150532D41646F6265", "ps");     
        FILE_TYPE_MAP.put("255044462d312e360d25", "pdf"); //Adobe Acrobat (pdf)   
        FILE_TYPE_MAP.put("2e524d46000000120001", "rmvb"); //rmvb/rm相同  
        FILE_TYPE_MAP.put("464c5601050000000900", "flv"); //flv与f4v相同  
        FILE_TYPE_MAP.put("00000020667479706973", "mp4"); 
        FILE_TYPE_MAP.put("49443303000000000f76", "mp3"); 
        FILE_TYPE_MAP.put("000001ba210001000180", "mpg"); //     
        FILE_TYPE_MAP.put("3026b2758e66cf11a6d9", "wmv"); //wmv与asf相同    
        FILE_TYPE_MAP.put("524946464694c9015741", "wav"); //Wave (wav)  
        FILE_TYPE_MAP.put("52494646d07d60074156", "avi");  
        FILE_TYPE_MAP.put("4d546864000000060001", "mid"); //MIDI (mid)   
        FILE_TYPE_MAP.put("504b0304140000000800", "zip");    
        FILE_TYPE_MAP.put("526172211a0700cf9073", "rar");   
        FILE_TYPE_MAP.put("235468697320636f6e66", "ini");   
        FILE_TYPE_MAP.put("504b03040a0000000000", "jar"); 
        FILE_TYPE_MAP.put("4d5a9000030000000400", "exe");//可执行文件
        FILE_TYPE_MAP.put("3c25402070616765206c", "jsp");//jsp文件
        FILE_TYPE_MAP.put("4d616e69666573742d56", "mf");//MF文件
        FILE_TYPE_MAP.put("3c3f786d6c2076657273", "xml");//xml文件
        FILE_TYPE_MAP.put("efbbbf2f2a0d0a53514c", "sql");//xml文件
        FILE_TYPE_MAP.put("7061636b616765207765", "java");//java文件
        FILE_TYPE_MAP.put("406563686f206f66660d", "bat");//bat文件
        FILE_TYPE_MAP.put("1f8b0800000000000000", "gz");//gz文件
        FILE_TYPE_MAP.put("6c6f67346a2e726f6f74", "properties");//bat文件
        FILE_TYPE_MAP.put("cafebabe0000002e0041", "class");//bat文件
        FILE_TYPE_MAP.put("49545346030000006000", "chm");//bat文件
        FILE_TYPE_MAP.put("04000000010000001300", "mxp");//bat文件
        FILE_TYPE_MAP.put("504b0304140006000800", "docx");//docx文件
        FILE_TYPE_MAP.put("d0cf11e0a1b11ae10000", "wps");//WPS文字wps、表格et、演示dps都是一样的
        FILE_TYPE_MAP.put("6431303a637265617465", "torrent");
        FILE_TYPE_MAP.put("494d4b48010100000200", "264");
        
          
        FILE_TYPE_MAP.put("6D6F6F76", "mov"); //Quicktime (mov)  
        FILE_TYPE_MAP.put("FF575043", "wpd"); //WordPerfect (wpd)   
        FILE_TYPE_MAP.put("CFAD12FEC5FD746F", "dbx"); //Outlook Express (dbx)     
        FILE_TYPE_MAP.put("2142444E", "pst"); //Outlook (pst)      
        FILE_TYPE_MAP.put("AC9EBD8F", "qdf"); //Quicken (qdf)     
        FILE_TYPE_MAP.put("E3828596", "pwl"); //Windows Password (pwl)         
        FILE_TYPE_MAP.put("2E7261FD", "ram"); //Real Audio (ram) 
    }  
  
    /**  
     * 得到上传文件的文件头  
     * @param src  
     * @return  
     */    
    private static String bytesToHexString(byte[] src){    
        StringBuilder stringBuilder = new StringBuilder();    
        if(null==src || 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 file 
     * @return 
     */  
    public static String getFileType(File file){  
        String res = null;
        FileInputStream fis = null;
        try{  
            fis = new FileInputStream(file);
            //获取文件头的前六位
            byte[] b = new byte[3];  
            fis.read(b, 0, b.length);  
            String fileCode = bytesToHexString(b); 
            Iterator<String> keyIter = FILE_TYPE_MAP.keySet().iterator();  
            while(keyIter.hasNext()){  
                String key = keyIter.next();		
                 //比较前几位是否相同就可以判断文件格式(相同格式文件文件头后面几位会有所变化)
                if(key.toLowerCase().startsWith(fileCode.toLowerCase()) || fileCode.toLowerCase().startsWith(key.toLowerCase())){  
                    res = FILE_TYPE_MAP.get(key);  
                    break;  
                }  
            }
            log.info("文件头:"+fileCode+"-----文件类型:"+res);
            fis.close();
        }catch(FileNotFoundException e){
            e.printStackTrace();    
        }catch (IOException e){  
            e.printStackTrace();    
        }finally {
            try {
                fis.close();
            }catch (IOException e) {
                e.printStackTrace();
            }
        }    
        return res;  
    }
    
}


<think>好的,用户问的是如何用Java根据判断文件格式。首先,我需要回想一下常见的处理方法。通常,每种文件格式都有特定的魔数(Magic Number),也就是文件头的几个字节,比如PNG文件的头是89 50 4E 47,JPEG是FF D8 FF E0等。所以,用户可能需要通过读取文件的头信息来识别类型。 接下来,用户可能想知道具体的实现方法。我需要考虑如何用Java读取文件的输入流,提取前面的字节,然后和已知的魔数进行比对。可能需要一个工具类,里面包含不同文件类型的魔数和对应的MIME类型或扩展名。 然后,用户的需求可能不仅仅是识别几个常见的类型,可能需要扩展性,比如支持更多的文件类型。因此,在代码示例中应该展示如何添加自定义的魔数,这样用户可以根据需要扩展。 另外,用户可能会关心异常处理,比如文件太小,无法读取足够的字节,或者IO异常。所以在示例代码里需要处理这些情况,比如捕获IOException,检查字节数组的长度。 还有,用户可能需要知道如何在实际应用中使用这个方法。比如传入一个File对象或者InputStream,然后调用工具类的方法获取类型。这样代码示例需要展示完整的流程,从读取文件到获取结果。 同时,需要注意Java中处理字节的方式,比如大端序和小端序的问题。例如,PDF文件的魔数是25 50 44 46,对应的字节是"%PDF",而Java读取字节的时候是按顺序的,所以直接比对字节数组即可。 还要考虑性能问题,比如每次读取文件头会不会影响效率,但通常读取前几十个字节对性能影响不大。不过,如果用户需要处理非常大的文件,可能需要优化,但一般情况下不需要。 用户可能没有提到具体的应用场景,但常见的情况是上传文件时需要验证类型,防止错误或恶意文件。这时候,仅仅根据文件扩展名是不够的,因为用户可以修改扩展名,所以通过魔数检测更可靠。 最后,要提醒用户魔数检测并非100%可靠,某些文件类型可能有重叠的魔数,或者没有明显的魔数,这时候可能需要结合其他方法,如内容分析。但大多数常见格式使用魔数是足够的。 总结下来,回答需要包括魔数的概念、实现步骤、代码示例、异常处理、扩展方法以及注意事项,这样用户才能全面了解如何在Java根据判断文件格式。</think>在 Java 中通过文件流判断文件格式,通常需要基于 **文件头(Magic Number)** 进行识别。以下是具体实现方法及示例: --- ### 一、核心原理 1. **文件头特征**:每种文件格式有独特的起始字节(如 PNG 开头为 `89 50 4E 47`,PDF 开头为 `25 50 44 46`) 2. **读取策略**:读取文件流的前 N 个字节,与预定义的格式特征比对 --- ### 二、实现步骤 #### 1. 定义文件头特征库 ```java private static final Map<String, String> FILE_TYPES = new HashMap<>(); static { // 格式: <文件头十六进制字符串>, <文件类型> FILE_TYPES.put("FFD8FF", "jpg"); FILE_TYPES.put("89504E47", "png"); FILE_TYPES.put("25504446", "pdf"); FILE_TYPES.put("504B0304", "zip"); FILE_TYPES.put("52617221", "rar"); FILE_TYPES.put("494433", "mp3"); } ``` #### 2. 读取文件头字节 ```java public static String getFileHeader(InputStream is) throws IOException { byte[] buffer = new byte[8]; // 读取前8字节(可调整长度) try (BufferedInputStream bis = new BufferedInputStream(is)) { bis.mark(8); int read = bis.read(buffer, 0, 8); if (read < 1) return ""; bis.reset(); return bytesToHex(buffer); } } // 字节数组转十六进制字符串 private static String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02X", b)); } return sb.toString(); } ``` #### 3. 匹配文件类型 ```java public static String detectFileType(InputStream is) throws IOException { String header = getFileHeader(is); for (Map.Entry<String, String> entry : FILE_TYPES.entrySet()) { if (header.startsWith(entry.getKey())) { return entry.getValue(); } } return "unknown"; } ``` --- ### 三、使用示例 ```java public static void main(String[] args) { File file = new File("test.jpg"); try (InputStream is = new FileInputStream(file)) { String fileType = detectFileType(is); System.out.println("文件类型: " + fileType); // 输出: jpg } catch (IOException e) { e.printStackTrace(); } } ``` --- ### 四、扩展说明 1. **支持更多格式**:补充 `FILE_TYPES` 的特征值 ```java FILE_TYPES.put("47494638", "gif"); // GIF FILE_TYPES.put("66747970", "mp4"); // MP4 ``` 2. **处理特殊情况**: - 某些格式可能共享相同头部(如 `.docx` 与 `.pptx` 都是 ZIP 格式) - 需要结合其他验证逻辑(如检查 ZIP 包内的特定文件) --- ### 五、注意事项 1. **字节读取长度**:不同格式需要读取不同长度的头信息(例如 BMP 需要 2 字节,Java Class 文件需要 4 字节) 2. **流重置操作**:使用 `mark()/reset()` 避免影响后续流处理 3. **大端序/小端序**:某些格式需要处理字节顺序(如 UTF 编码的 BOM 头) --- 通过这种方法可以快速识别常见文件格式,实际项目中建议使用成熟的库如: - Apache Tika (`tika-core`) - Files.probeContentType() (NIO 方法) - `javax.activation.MimetypesFileTypeMap`
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值