package com.logo.eshow.util; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Created with IntelliJ IDEA. * User: yangyao * Date: 13-12-4 * 解析Bin文件 */ public class ParseBinUtil { /** * 表示计算类型 * @author Ly * */ private static enum ACOUNT_TYPE {III_,aVR_,aVL_,aVF_}; private static Integer SECOUNDSIZE = null; /** * 解析当前bin文件 * @return 返回数据集合(包含头文件)<br> * 结构如下: * 文件头(包含身份证号,开始记录时间,文件版本号,其他)<br> * [0],[1],[2],[3].....[1023]<br> * 第一秒数据<br> * V6 <br> * [0],[1],[2],[3].....[1023]<br> * I<br> * [0],[1],[2],[3].....[1023]<br> * II<br> * [0],[1],[2],[3].....[1023]<br> * V2<br> * [0],[1],[2],[3].....[1023]<br> * V3<br> * [0],[1],[2],[3].....[1023]<br> * V4<br> * [0],[1],[2],[3].....[1023]<br> * V5<br> * [0],[1],[2],[3].....[1023]<br> * V1<br> * [0],[1],[2],[3].....[1023]<br> * 运动传感器数据<br> * [0],[1],[2],[3].....[1023]<br> * ....<br> * 第N秒数据<br> * @throws IOException 抛出IO异常<br> * @param binFilePath 文件路径 */ private static List<List<String[]>> parseVoltageBinData(String binFilePath,int startSecond,int endSecond) throws IOException{ //声明用于保存数据总集合 //声明用于保存数据总集合 int second = 0;//定义一个秒数 List<List<String[]>> list = new ArrayList<List<String[]>>(); DataInputStream read = new DataInputStream(new FileInputStream(new File(binFilePath))); byte []bs = new byte[1024*9];//一次读取1024KB byte []head = new byte[1024]; int index = 0;//当前循环秒数索引 List<String[]> lis = new ArrayList<String[]>();//用于保存每秒数据块集合 while (read.read(index==0?head:bs)!=-1) {//当索引为0读取头部文件,反之读取1*1024数据 String [] strs = new String[1024];//每读取1KB就重新申明数组 if(second == endSecond)//循环到指定描述就终止读取 break; if(index > 0){//读取非头文件 second +=1;//每读一次加一秒 if(second >= startSecond){//循环到指定秒时候开始将数据写入集合 int j = 0;//用于读取每个块的索引 for (int i = 0; i < bs.length; i++) {//读取当前非头文件1024 * 9 String str = bs[i] + ""; if(!str.equals("null"))//非空判断 strs[j] = str; j++; if((i+1)%1024==0){//循环到下一个块 if(strs != null)//当前快不为空 lis.add(strs); strs = new String[1024]; j = 0;//循环结束,准备读取下一秒数据 } } list.add(lis); lis = new ArrayList<String[]>();//9次后置空 } }else{//读取头文件 for (int i = 0; i < strs.length; i++) {//读取当前头文件1KB strs[i] = strs[i] + ""; } lis.add(strs);//加入当前 list.add(lis);//加入总的集合中 lis = new ArrayList<String[]>(); } index +=1; } index = 0; int secondSum = 0; while (read.read(index==0?head:bs)!=-1) { if(index>0){ secondSum+=1; } index +=1; } ParseBinUtil.SECOUNDSIZE = secondSum;//计算总页数 read.close(); return list; } /** * 解析每秒心电数据块(包含9个块) * @param list * 每秒心电数据包含9个数据块 * 每个块包含如下信息: * (标识信息:标示头,记录类型,时间戳,保留字节(0-23);数据类容(24-1023)) */ private static Map<String, List<Double[]>> parseBinDataList(List<List<String[]>> list){ List<List<List<Double>>> allDataPices = new ArrayList<List<List<Double>>>(); Map<String, List<Double[]>> finalData = ParseBinUtil.initMap();//初始化集合 list.remove(0);//忽略头文件 for (List<String[]> list2 : list) {//循环所有秒 //声明保存当前一秒所有数据块数据集合 List<List<Double>> dataPices = new ArrayList<List<Double>>(); for (int i=0;i<list2.size();i++) {//遍历当前一秒数据中所有块 if(i<8)//忽略运动传感数据 finalData = parsePice(list2.get(i),finalData); } allDataPices.add(dataPices); } return finalData; } /** * 初始化Map集合 * @return Map */ private static Map<String, List<Double[]>> initMap(){ String [] pices = {"V6","I","II","V2","V3","V4","V5","V1","III","aVR","aVL","aVF"}; Map<String, List<Double[]>> map = new HashMap<String, List<Double[]>>(); for (int i = 0; i < pices.length; i++) { List<Double[]> list = new ArrayList<Double[]>(); map.put(pices[i], list); } return map; } /** * 根据指定字符获取数据类型 * @param str1 字符1 * @param str2 字符2 * @return String */ private static String getKey(String str1,String str2){ int sum = Integer.valueOf(str1) + Integer.valueOf(str2); if(sum == 0) return "V6"; if(sum == 1) return "I"; if(sum == 2) return "II"; if(sum == 3) return "V2"; if(sum == 4) return "V3"; if(sum == 5) return "V4"; if(sum == 6) return "V5"; if(sum == 7) return "V1"; return "NULL"; } /** * 解析单个心电数据块 * @param strs 当前心电块的数据数组 * @return 返回当前数据块内容 * <br> * 每两个字节心电数值,分高低字节,每秒采样500次(1000/2) * 高字节计算方式:Integer.valueOf(strs[i]) + Integer.valueOf(strs[i-1]); * 低字节计算方式:(Integer.valueOf(strs[i]) + Integer.valueOf(strs[i-1])) + 1; * 2个字节得出一个电压值 * 电压值计算方式:((高字节<<8) + 低字节 - 32768) / 2621.4; * 注:运动传感器数据与上不同,每四个字节一个数值,前三次代表X,Y,Z三个运动方向数据,第四个字节暂无意义 * 每秒采样250次(1000/4) */ private static Map<String, List<Double[]>> parsePice(String [] strs,Map<String, List<Double[]>> finalData){ //数据块内容 Double[] dataPices = new Double[500]; int dataPices_index = 0;//数据块内容索引 for (int i = 24; i < strs.length; i++) {//忽略前24位,只解析后1000位 if(i==1023) break; int bigEndian = Integer.valueOf(strs[i]);//高字节 int smallEndian = Integer.valueOf(strs[i+1]);//低字节 //计算电压值 Double voltageValue = ((bigEndian<<8) + smallEndian - 32768)/2621.4; dataPices[dataPices_index] = voltageValue; if(i%2==0) dataPices_index++; } finalData.get(ParseBinUtil.getKey(strs[4], strs[5])).add(dataPices);//加入到集合中 return finalData; } /** * 计算特殊数据,需要两个固定参数I块内容,II_块内容 * @param I_ I数据块 * @param II_ II数据块 * @param type 计算类型 ,包括III,aVR,aVL,aVF * @return */ private static Double[] accountAnother (Double [] I_,Double [] II_,ACOUNT_TYPE type){ Double[] nowPice = new Double[500]; for(int i=0;i<I_.length;i++){ if(type == ACOUNT_TYPE.III_) nowPice[i]= II_[i] - I_[i];//算出特殊块的每秒中对应的数据 if(type == ACOUNT_TYPE.aVR_) nowPice[i] = -0.5 * ( II_[i] + I_[i] ); if(type == ACOUNT_TYPE.aVL_) nowPice[i] = (I_[i] - 0.5 ) * II_[i]; if(type == ACOUNT_TYPE.aVF_) nowPice[i] = (II_[i] - 0.5) * I_[i]; } return nowPice; } /** * 测试输出 * @param list */ private static void write(List<List<Double>> list){ int index = 1; for (List<Double> list2 : list) {//循环当前数据块所有数据 System.out.println("V6第" + index + "数据如下:"); for (Double double1 : list2) {// System.out.println(double1); } System.out.println("共有:" + list2.size()); index ++; } } /** * 获取对用描述数据 * @param binFilePath 文件地址 * @param startSecond 从第几秒开始 * @param endSecond 结束秒数,总共需要获取多少秒 * @return Map<名称, List<Double[]>> * @throws IOException */ public static Map<String, List<Double[]>> getPageMap (String binFilePath,int startSecond,int endSecond) throws Exception{ List<List<String[]>> voltageBinData = ParseBinUtil.parseVoltageBinData(binFilePath,startSecond,endSecond); Map<String, List<Double[]>> allData = ParseBinUtil.parseBinDataList(voltageBinData); //处理特殊数据 for (int i = 0; i < allData.get("I").size(); i++) { allData.get("III"). add(ParseBinUtil.accountAnother (allData.get("I").get(i), allData.get("II").get(i), ParseBinUtil.ACOUNT_TYPE.III_)); allData.get("aVF"). add(ParseBinUtil.accountAnother (allData.get("I").get(i), allData.get("II").get(i), ParseBinUtil.ACOUNT_TYPE.aVF_)); allData.get("aVL"). add(ParseBinUtil.accountAnother (allData.get("I").get(i), allData.get("II").get(i), ParseBinUtil.ACOUNT_TYPE.aVL_)); allData.get("aVR"). add(ParseBinUtil.accountAnother (allData.get("I").get(i), allData.get("II").get(i), ParseBinUtil.ACOUNT_TYPE.aVR_)); } return allData; } /** * 获取XYDataset格式数据 * @param binFilePath 文件地址 * @param startSecond 从第几秒开始 * @param endSecond 结束秒数,总共需要获取多少秒 * @throws IOException */ public static XYSeriesCollection getXYDataset(String binFilePath,int startSecond,int endSecond) { XYSeriesCollection xyseriescollection = new XYSeriesCollection(); Map<String, List<Double[]>> pageData = null; try{ pageData = ParseBinUtil.getPageMap(binFilePath,startSecond,endSecond); }catch(Exception e){ e.printStackTrace(); } String [] pices = {"I","II","III","aVR","aVL","aVF","V1","V2","V3","V4","V5","V6"}; Map<String,XYSeries> map = new HashMap<String, XYSeries>(); for(int i=0;i<pices.length;i++){ map.put(pices[i], new XYSeries(pices[i])); } //初始化数据 int k = 12;//导联 for(String key : pageData.keySet()){ k--; int i = 0; for(Double [] db : pageData.get(key)){//循环每秒数据 for(Double d : db){ map.get(key).add(0.002d * i * 2.500d, d + 3*k +2.5d); i++; } } } for(String str : pices){ xyseriescollection.addSeries(map.get(str)); } return xyseriescollection; } /** * 获取总的秒数 * @return */ public static Integer getPageSize(){ return SECOUNDSIZE; } /** * 测试方法 * @param args */ public static void main(String[] args) { String binFilePath = "E:\\WORK-TOOLS\\test.bin"; try { Map<String, List<Double[]>> mapData = ParseBinUtil.getPageMap(binFilePath,10,15); String [] pices = {"V6","I","II","V2","V3","V4","V5","V1","III","aVR","aVL","aVF"}; for (int i = 0; i < pices.length; i++) { System.out.println(mapData.get(pices[i]).get(0).length); } Double [] db = mapData.get("III").get(0); for (int i = 0; i < db.length; i++) { System.out.println(db[i]); } System.out.println("共有数据 :"+ParseBinUtil.SECOUNDSIZE); // ParseBinUtil.write(mapData.get("III")); } catch (Exception e) { e.printStackTrace(); } } }