当前位置:文档之家› java解析FSN文件

java解析FSN文件

package action;import java.util.ArrayList;import tools.FsnTools;import bean.FsnBody;import bean.FsnModel;public class FsnReaderAction {public final static int intstep=2; //Uint16字节长度public final static int stringstep=4; //Uint32字节长度public final static int fsnHeadLengh=32;//fsn文件头字节长度public final static int fsnPerBodyNoImg=100; //fsn文件体每条记录,不包括图像信息的字节长度public final static int fsnPerBodyImg=1644; //fsn文件体每条记录,包括图像信息的字节长度public int filePos=0; //fsn文件字节流当前指针位置public FsnModel fm; //本实例解析的FsnMedel对象public String fsnFilePath ;//FSN文件的存储完整路径,包括文件名public FsnReaderAction(String filePath){this.fsnFilePath=filePath;}public FsnModel readFsnFile() throws Exception {// FsnModel ret=null;try{this.fm=new FsnModel(this.fsnFilePath);//hzyimport 把文件转成字节流数组byte[] fsnbytes =FsnTools.toByteArray(this.fsnFilePath);this.fm.setSize(fsnbytes.length);System.out.println("File Lengh: "+fsnbytes.length);// 读取头文件setHead(fsnbytes);long counter = this.fm.getCounter(); // 冠字号信息条数//System.out.println("this.fm.getHeadString()[2]="+this.fm.getHeadStr ing()[2]);int size = this.fm.getHeadString()[2] != 0x2D ? fsnPerBodyImg: fsnPerBodyNoImg;// System.out.println("this.fm.getHeadString()[2]="+this.fm.getHeadString()[2] );// System.out.println("counter ="+counter);// System.out.println("size="+size);// System.out.println("counter =* size"+counter * size);// System.out.println("fsnHeadLengh="+fsnHeadLengh);//如果fsn文件的长度合一致if (counter * size + fsnHeadLengh == fsnbytes.length) {ArrayList<FsnBody> list = new ArrayList<FsnBody>();long ValutaSum=0;for (int i = 0; i < counter; i++) {FsnBody body = new FsnBody();boolean noException=false; //处理过程中没有异常//每条fsn信息均从i * size + 32(头的长度)处起始int thisPosSart=i * size + fsnHeadLengh;//此处处理非常重要,在读取图片文件前一定要做处理因为图片字节流长度固定,644位,getSnoExpImg方法只读到图片信息中有数据部分对应的字节流,后面的都是空值,将不再读取//某条图片数据读完以后,filePos不一定会移至这个图片数据对应的结尾位置,要在读取下一条数据时,强制将filePos指向下一条图片信息对应字节流起始位置if(filePos<thisPosSart){filePos=thisPosSart;}body = getSnoExpImg(fsnbytes);body.setRecordNum(i+1); //此条fsn记录在fsn文件中的顺序ValutaSum += body.getValuta();if(size!=fsnPerBodyNoImg){testSnoImg(fsnbytes); //校验图片数据合法性,如果不合法,将抛出异//map.put("ImageSno", imageSno); //图片BufferedImage 对象,不能将此数据放入map,一是数据量大时内存溢出,二是效率大打折byte[] imgbytes=FsnTools.byteCopy(fsnbytes, thisPosSart+fsnPerBodyNoImg, size-fsnPerBodyNoImg);body.setImageBytes(imgbytes); //图片字节数组数据imgbytes=null; //及时释放图片字节数组对象,释放内}else{//map.put("ImageSno", null);body.setImageBytes(null);}noException=true;if(noException){ //当没有异常时记录解析数据list.add(body);}else{if(this.fm.isPermitException()){ //当有异常时,如果fsn配置文件允许记录异常,则记录,否则不记录list.add(body);}}}this.fm.setBodys(list) ;}}catch(Exception e){this.fm.setAnalysisExcepted(true);this.fm.setAnalysisErrorMsg(e.getMessage());//写日志}return this.fm;}/*** 获取Fsn每条记录中的图片对象* @param fsnBytes fsn文件的byte字节流对* @return*/public void testSnoImg(byte[] fsnBytes) throws Exception{ //冠字号码的个数int num = parseInt(fsnBytes);//每个冠字号码的图像宽int height = parseInt(fsnBytes);int width = parseInt(fsnBytes);int Reserve2 = parseInt(fsnBytes);// 图片三维不能小于0if(num<=0||height<=0||width<=0){throw new Exception("图片数据读取失败,长宽和字符数均不能小于等于0");}//冠字号码个数不能多于12if(num>12){throw new Exception("图片数据读取失败,冠字号码个数不能多");}//图片大小不能多于图片缓冲区的总大小,减去108位,包括100位其他字段和8位图像metalong mutiall = 4 * width * num;if (mutiall > fsnPerBodyImg - 108){throw new Exception("图像数据读取失败,图像长度大于图像缓冲器长度");}//int i = 0;//while ( i < width * num) {//byte[] pic=parseByte(fsnBytes,4);//String s=MessageUtil.toBinaryString(pic);//i++;//}}public FsnBody getSnoExpImg(byte[] fsnBytes) {FsnBody body = new FsnBody();// 设置日期时间int data = parseInt(fsnBytes);int time = parseInt(fsnBytes);// System.out.println("data="+data);// System.out.println("time="+time);/*if(time<0){time=-time;}*/int y = data >> 9;int m = (data - (y << 9)) >> 5;int d = data - (y << 9) - (m << 5);int hh = time >> 11;int mm = (time - (hh << 11)) >> 5;int ss = (time - (hh << 11) - (mm << 5)) << 1;/*String DateStr= StrUtil.numAddZero(String.valueOf((y + 1980) ),4)+ "-" + StrUtil.numAddZero(String.valueOf(m),2) + "-" +StrUtil.numAddZero(String.valueOf(d),2);String TimeStr=hh + ":" + mm+ ":" + ss;body.setDateStr(DateStr);body.setTimeStr( TimeStr);//*///*StringBuffer DateBuf=new StringBuffer();StringBuffer TimeBuf=new StringBuffer();DateBuf.append( y + 1980);DateBuf.append( "-");DateBuf.append( FsnTools.numAddZero(m,2) );DateBuf.append( "-");DateBuf.append( FsnTools.numAddZero(d,2) );TimeBuf.append(FsnTools.numAddZero(hh,2) );TimeBuf.append(":");TimeBuf.append(FsnTools.numAddZero(mm,2) );TimeBuf.append(":");TimeBuf.append(FsnTools.numAddZero(ss,2 ));body.setDateStr(DateBuf.toString());body.setTimeStr( TimeBuf.toString());body.setDateStr(DateBuf.toString());body.setTimeStr( TimeBuf.toString());body.setDateTime( body.getDateStr() + " " + body.getTimeStr());// 设置货币真假残和旧币标志body.setTfFlag(parseInt(fsnBytes));// 设置货币错误StringBuffer errorCode = new StringBuffer();/*for (int i = 0; i < 3; i++) {int code = parseInt(fsnBytes);if (code < 13 && code > 0) {errorCode += code + ",";}}if ("1".equals(map.get("TfFlag")))errorCode = errorCode.substring(0, stIndexOf(","));elseerrorCode = "0";*/for (int i = 0; i < 3; i++) {int code = parseInt(fsnBytes);if(i==0){errorCode.append(code);}else{errorCode.append(":") ;errorCode.append(code);}}body.setErrorCode(errorCode.toString());// 设置币种标志String moneyFlag = "";for (int i = 0; i < 4; i++) {int flag = parseInt(fsnBytes);if (flag != 0) {moneyFlag += (char) flag;}}body.setMoneyFlag( moneyFlag);// 设置年版或版本号标志int ver = parseInt(fsnBytes);//body.setVer(FsnTool.deMoneyVer(ver));body.setVer(ver);// 设置币body.setValuta(parseInt(fsnBytes));// 设置冠字号位body.setCharNum(parseInt(fsnBytes));// 设置冠字StringBuffer no = new StringBuffer();for (int i = 0; i < 12; i++) {int No = parseInt(fsnBytes);if (No != 0)no.append( (char) No);}body.setSno(no.toString());// 设置机具编号StringBuffer machineSNo =new StringBuffer();for (int i = 0; i < 24; i++) {int Msno = parseInt(fsnBytes);if (Msno != 0)machineSNo.append( (char) Msno);}body.setMachineSno( machineSNo.toString());// 设置冠字号保留字body.setReserve1( parseInt(fsnBytes));// System.out.println("时间="+body.getDateStr() + " " +body.getTimeStr()+"|真假币标志="+body.getTfFlag()+"|表示最多3组假币特征码="+body.getErrorCode()+"|"+// "|币种标志="+body.getMoneyFlag()+"|年版或版本号标志="+body.getVer()+"|币值="+body.getValuta()+"|冠字号码字符数="+body.getCharNum()+"|存放识别的冠字号码="+// body.getSno()+"|机具编号="+body.getMachineSno()+"|保留字1="+body.getRecordNum());return body;}public void setHead(byte[] fsnBytes) throws Exception { this.filePos=0; //读取文件头数据的当前指针位置,设置字节位移从0开始if(this.fm==null){this.fm=new FsnModel(this.fsnFilePath);}int[] headStart = new int[4];for (int i = 0; i < 4; i++) {headStart[i] = parseInt(fsnBytes);// System.out.println("headStart["+i+"]="+headStart[i]);}fm.setHeadStart(headStart);int[] headString = new int[6];for (int i = 0; i < 6; i++) {headString[i] = parseInt(fsnBytes);// System.out.println("headString["+i+"] ="+headString[i]);}fm.setHeadString(headString);long counter =parseLong(fsnBytes);// System.out.println("counter="+counter);fm.setCounter(counter);int[] headEnd = new int[4];for (int i = 0; i < 4; i++) {headEnd[i] = parseInt(fsnBytes);// System.out.println("headEnd["+i+"]="+headEnd[i]);}fm.setHeadEnd(headEnd);}public int parseInt(byte[] fsnBytes){intret=(int)FsnTools.demarshallintLittle(fsnBytes,filePos,intstep);this.filePos +=intstep;// System.out.println("this.filePos="+this.filePos+"||ret="+ret);return ret;}public long parseLong(byte[] fsnBytes){longret=FsnTools.demarshallintLittle(fsnBytes,filePos,stringstep);this.filePos +=stringstep;return ret;}public byte[] parseByte(byte[] fsnBytes,int length){byte[] ret=FsnTools.convertByteMarshall(fsnBytes,filePos,length);this.filePos +=length;return ret;}}package bean;public class FsnBody {private String DateStr; //验钞启动日期private String TimeStr; //验钞启动时间/**日期+时间* 指定年月日的日期数据的产生算法为: Date = ((Year-1980)<<9) + (Month<<5) + Day其中:Year为年份,大于等于1980;Month为月份;Day为日;指定时分秒的时间数据产生算法为:Time = (Hour<<11) + (Minute<<5) + (Second>>1)其中:0≤Hour < 24,0≤Minute < 60,0≤Second < 60*/private String DateTime; //验钞启动日期+时间private int TfFlag; //真假币标志,0为假币或可疑币,1为真币,2为残币(清分机适用),3为旧币(清分机适用);private String ErrorCode; //表示最多3组假币特征码(特征码有12种,分别为1,2,3,4,5,6,7,8,9,10,11,12),真币时填0;如果只有一组特征码,把特征码填在ErrorCode[0],则其余两组填0;如果有两组特征码,把特征码填在ErrorCode[0]和ErrorCode[1],剩余的一组填0private String MoneyFlag; //币种标志,最多4位大写ASCII英文字母,不足4位的其余位填0:CNY:人民币private int Ver; //年版或版本号标志;人民币用作年版标志,值填0,1,2,分别代表1990,1999,2005三个年版,可根据实际情况扩充;其余币种填9999(表示不考虑年版);private int Valuta; //币值,最大币值为50000private int CharNum; //冠字号码字符数,指明存储在数组SNo的号码个数;private String Sno; //存放识别的冠字号码,每个数组元素存放一位号码(ASCII 字符),最多12位,不足12位的其余位填0;private String MachineSno; //机具编号,必须为24位,每个数组元素存放一位ASCII字符,不足24位的其余位填0;private int Reserve1; //保留字1private int RecordNum; //冠字号信息在Fsn文件中的行号,从1开始private byte[] ImageBytes; //冠字号信息的图片数据字节数组,保存的原始格式,未转换private String ImgStr; //图片压缩后的字符串private String accNo=""; //冠字号信息产生的账号,Atm等自助存取款机才会有此值public String getDateStr() {return DateStr;}public void setDateStr(String dateStr) {DateStr = dateStr;}public String getTimeStr() {return TimeStr;}public void setTimeStr(String timeStr) {TimeStr = timeStr;}public String getDateTime() {return DateTime;}public void setDateTime(String dateTime) {DateTime = dateTime;}public int getTfFlag() {return TfFlag;}public void setTfFlag(int tfFlag) {TfFlag = tfFlag;}public String getErrorCode() {return ErrorCode;}public void setErrorCode(String errorCode) { ErrorCode = errorCode;}public String getMoneyFlag() {return MoneyFlag;}public void setMoneyFlag(String moneyFlag) { MoneyFlag = moneyFlag;}public int getVer() {return Ver;}public void setVer(int ver) {Ver = ver;}public int getValuta() {return Valuta;}public void setValuta(int valuta) {Valuta = valuta;}public int getCharNum() {return CharNum;}public void setCharNum(int charNum) {CharNum = charNum;}public String getSno() {return Sno;}public void setSno(String sno) {Sno = sno;}public String getMachineSno() {return MachineSno;}public void setMachineSno(String machineSno) { MachineSno = machineSno;}public int getReserve1() {return Reserve1;}public void setReserve1(int reserve1) { Reserve1 = reserve1;}public int getRecordNum() {return RecordNum;}public void setRecordNum(int recordNum) {RecordNum = recordNum;}public byte[] getImageBytes() {return ImageBytes;}public void setImageBytes(byte[] imageBytes) {ImageBytes = imageBytes;}public String getImgStr() {return ImgStr;}public void setImgStr(String imgStr) {ImgStr = imgStr;}public String getAccNo() {return accNo;}public void setAccNo(String accNo) {this.accNo = accNo;}}package bean;import java.util.ArrayList;public class FsnModel implements Comparable<FsnModel>{private int[] headStart; // Fsn文件头起始标志,由4个16比特无符号数据组成,内容为十进制数,分别是20,10,7,26;private int[] headString; // Fsn文件体内容,详情参见<冠字号码文件格式说明.doc>private long counter; // 32比特无符号数值,记录当前冠字号码的记录数。

相关主题