package com.dy.common.softUpgrade.parse; import cn.hutool.core.util.HexUtil; import com.dy.common.util.ByteUtil; import com.dy.common.util.CRC16; import java.io.*; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; /** * @Author: liurunyu * @Date: 2024/11/2 8:51 * @Description */ public class HexFileParse { private static final int hexFileMinLine = 4 ; private static final int lineHeadEndIndex = 9 ; private static final int lineValidCharCount = 43 ;//每行有效字符(冒号与十六进制)个数,例如“:1096C000DC96010010020020203E00000441000052”,但倒数第3行不受限制 private static final int bytesSplitUnit512 = 512 ; public static void main(String[] args) throws Exception{ boolean fromBytes = false ; HexFileParse obj = new HexFileParse() ; if(!fromBytes){ String filePath = "D:\\hexFile\\YuanMu_20250116_01.hex"; //File file = new File(filePath) ; HexFileVo vo = obj.doParse(filePath) ; System.out.println(vo.toString()); }else{ String filePath = "D:\\hexFile\\YuanMu_20250116_01.hex"; File file = new File(filePath) ; byte[] fileContent = new byte[(int)file.length()] ; FileInputStream fileInputStream = new FileInputStream(file) ; fileInputStream.read(fileContent) ; HexFileVo vo = obj.doParse(fileContent) ; System.out.println(vo.toString()); } } /** * 解析Hex文件 * @param path * @return * @throws Exception */ public HexFileVo doParse(String path) throws Exception { File file = new File(path) ; return this.doParse(file) ; } /** * 解析Hex文件 * @param file * @return * @throws Exception */ public HexFileVo doParse(File file) throws Exception{ if(file == null){ throw new Exception("Hex文件对象为null") ; } if(!file.exists()){ throw new Exception("Hex文件不存在") ; } Stream linesStream = new BufferedReader(new FileReader(file)).lines() ; List lineList = linesStream.toList() ; HexFileVo vo = new HexFileVo() ; this.checkAndCalculate(vo, lineList); this.parse(vo, lineList); this.splitBytesByUnit512(vo); this.calculateCrc(vo); return vo ; } /** * 解析Hex文件 * @param fileContent * @return * @throws Exception */ public HexFileVo doParse(byte[] fileContent) throws Exception{ if(fileContent == null || fileContent.length == 0){ throw new Exception("Hex文件对象为null") ; } ByteArrayInputStream byteInputStream = new ByteArrayInputStream(fileContent); Stream linesStream = new BufferedReader(new InputStreamReader(byteInputStream)).lines() ; List lineList = linesStream.toList() ; HexFileVo vo = new HexFileVo() ; this.checkAndCalculate(vo, lineList); this.parse(vo, lineList); this.splitBytesByUnit512(vo); this.calculateCrc(vo); return vo ; } /** * 合法性检查,并计算数据包数 * @param vo * @param lineList * @throws Exception */ private void checkAndCalculate(HexFileVo vo, List lineList) throws Exception{ if(lineList == null){ throw new Exception("Hex文件内容为空") ; } vo.totalLines = lineList.size() ; if(vo.totalLines <= 0){ throw new Exception("Hex文件内容为空") ; } if(vo.totalLines < hexFileMinLine){ throw new Exception("Hex文件内容行数" + vo.totalLines + "不正确(最小行数" + hexFileMinLine +")") ; } vo.calculateBytes = ((((vo.totalLines - 4) * 32) / 1024) + ((((vo.totalLines - 4) * 32) % 1024) > 0?1 : 0)) * 512 ; } /** * 解析Hex文件内容,组合成一个大数据包 * @param vo * @param lineList * @throws Exception */ private void parse(HexFileVo vo, List lineList) throws Exception{ int counter = 0 ; for(String line : lineList){ if(counter == 0){ // 文件头 }else if(counter == vo.totalLines - 2){ // 文件尾倒数第2行 }else if(counter == vo.totalLines - 1){ // 文件尾倒数第1行 }else{ // 文件内容 if(line == null){ vo.errors.add("第" + counter + "行内容为空") ; }else{ line = line.trim() ; if(line.length() == 0){ vo.errors.add("第" + counter + "行内容为空") ; }else{ if(!line.startsWith(":")){ vo.errors.add("第" + counter + "行内容不是以:开头") ; }else{ if(counter != vo.totalLines - 3 && line.length() != lineValidCharCount){ //无效数据,舍弃本行数据 }else{ line = line.substring(lineHeadEndIndex, line.length() - 2) ; if(vo.bytes.length == 0){ vo.bytes = HexUtil.decodeHex(line) ; }else{ byte[] bytes = HexUtil.decodeHex(line) ; vo.bytes = ByteUtil.bytesMerge(vo.bytes, bytes) ; } } } } } } counter ++ ; } } /** * 以512为单位分割数据包 * @param bytes */ public List splitBytesByUnit512(byte[] bytes){ List listByte512 = new ArrayList<>(); if(bytes != null && bytes.length > 0){ int index = 0 ; while (true){ if(index < bytes.length){ byte[] bs = ByteUtil.bytesSplit(bytes, index, bytesSplitUnit512) ; listByte512.add(bs) ; }else{ break ; } index += bytesSplitUnit512; } } return listByte512 ; } /** * 以512为单位分割数据包 * @param vo */ private void splitBytesByUnit512(HexFileVo vo){ if(vo.bytes != null && vo.bytes.length > 0){ vo.realBytes += vo.bytes.length ; int index = 0 ; while (true){ if(index < vo.bytes.length){ byte[] bytes = ByteUtil.bytesSplit(vo.bytes, index, bytesSplitUnit512) ; vo.listByte512.add(bytes) ; vo.totalBytes512 += bytes.length ; }else{ break ; } index += bytesSplitUnit512; } } } /** * 计算CRC16 * @param vo */ private void calculateCrc(HexFileVo vo){ int crc = 0xffff ; if(vo.listByte512 != null && vo.listByte512.size() > 0){ CRC16 crc16 = new CRC16() ; for(byte[] bs : vo.listByte512){ crc = crc16.CRC16_table(bs.length, bs, crc) ; } } vo.bytesCrc16 = crc ; } }