java解析FSN文件
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
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);
// 图片三维不能小于0
if(num<=0||height<=0||width<=0){
throw new Exception("图片数据读取失败,长宽和字符数均不能小于等于0");
}
//冠字号码个数不能多于12
if(num>12){
throw new Exception("图片数据读取失败,冠字号码个数不能多");
}
//图片大小不能多于图片缓冲区的总大小,减去108位,包括100位其他字段和8位图像meta
long 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(","));
else
errorCode = "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){
int
ret=(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){
long
ret=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],剩余的一组填0
private String MoneyFlag; //币种标志,最多4位大写ASCII英文字母,不足4位的其余位填0:CNY:人民币
private int Ver; //年版或版本号标志;人民币用作年版标志,值填0,1,2,分别代表1990,1999,2005三个年版,可根据实际情况扩充;其余币种填9999(表示不考虑年版);
private int Valuta; //币值,最大币值为50000
private int CharNum; //冠字号码字符数,指明存储在数组SNo的号码个数;
private String Sno; //存放识别的冠字号码,每个数组元素存放一位号码(ASCII 字符),最多12位,不足12位的其余位填0;
private String MachineSno; //机具编号,必须为24位,每个数组元素存放一位ASCII字符,不足24位的其余位填0;
private int Reserve1; //保留字1
private 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比特无符号数值,记录当前冠字号码的记录数。
private int[] headEnd; // Fsn文件结束标志,由4个16比特无符号数据组成,内容为十进制数,数值分别是0,1,2,3。
private ArrayList<FsnBody> bodys; // Fsn记录报文体内容,每个对象以Map 方式存储。
private String filePath; // Fsn文件所在路径
private String fsnFileName;// fsn文件名,不包括扩展名
private String fsnFileNameWidthEx;// fsn文件名,包括扩展名
private boolean permitException = false; // 是否允许记录异常数据,默认
为不允许
private boolean analysisExcepted = false; // 本fsn文件是否解析异常private String analysisErrorMsg = ""; // 本fsn文件解析异常信息
private long size = 0; // Fsn文件大小
public FsnModel() {
}
public FsnModel(String filePath) throws Exception {
if (filePath == null || "".equals(filePath)) {
throw new Exception("文件名称不能为空");
}
setFilePath(filePath);
}
public int[] getHeadStart() {
return headStart;
}
public void setHeadStart(int[] headStart) {
this.headStart = headStart;
}
public int[] getHeadString() {
return headString;
}
public void setHeadString(int[] headString) {
this.headString = headString;
}
public long getCounter() {
return counter;
}
public void setCounter(long counter) {
this.counter = counter;
}
public int[] getHeadEnd() {
return headEnd;
}
public void setHeadEnd(int[] headEnd) {
this.headEnd = headEnd;
}
public ArrayList<FsnBody> getBodys() {
return bodys;
}
public void setBodys(ArrayList<FsnBody> bodys) {
this.bodys = bodys;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public String getFsnFileName() {
return fsnFileName;
}
public void setFsnFileName(String fsnFileName) {
this.fsnFileName = fsnFileName;
}
public String getFsnFileNameWidthEx() {
return fsnFileNameWidthEx;
}
public void setFsnFileNameWidthEx(String fsnFileNameWidthEx) { this.fsnFileNameWidthEx = fsnFileNameWidthEx;
}
public boolean isPermitException() {
return permitException;
}
public void setPermitException(boolean permitException) { this.permitException = permitException;
}
public boolean isAnalysisExcepted() {
return analysisExcepted;
}
public void setAnalysisExcepted(boolean analysisExcepted) { this.analysisExcepted = analysisExcepted;
}
public String getAnalysisErrorMsg() {
return analysisErrorMsg;
}
public void setAnalysisErrorMsg(String analysisErrorMsg) { this.analysisErrorMsg = analysisErrorMsg;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
@Override
public int compareTo(FsnModel o) {
return pareTo(o.fsnFileName);
}
}
package test;
import java.util.ArrayList;
import action.FsnReaderAction;
import bean.FsnBody;
import bean.FsnModel;
public class FsnTest {
/**
* @param args
*/
public static void main(String[] args) {
long l=System.currentTimeMillis();
String path=FsnTest.class.getResource("").getPath();
String FilePath=path+"test.FSN"; //读取fsn文件的path地址
FsnModel fm=null;
FsnReaderAction fr=new FsnReaderAction(FilePath);
try {
fm = fr.readFsnFile();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ArrayList<FsnBody> list = fm.getBodys();
System.out.println("共"+list.size()+"条记录");
StringBuffer sbf = new StringBuffer();
for(int i=0;i<list.size();i++){
FsnBody fsnBody = list.get(i);
sbf.append(fsnBody.getSno());
sbf.append(" ");
}
System.out.println("所有冠字号:"+sbf.toString());
System.out.println("处理时间:"+(System.currentTimeMillis()-l));
}
}。