解析BIN

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();
        }
    }

}



你可能感兴趣的:(解析BIN)