这几天由于工作需要,需要做一个报表比对工具(找出两张报表的差异)。需求如下
1、做一个客户端工具,采用java,可以不用GUI(考虑到,我目前只懂j2ee相关的技术,其实这个需求用python(python版本)来做是最合适的,可是我目前不会,当然后面我会学习下这们语言)
2、两张报表的比队列需要灵活配置,通过配置文件来控制需要比对的列(可以是一列,可以是多列)
3、需要找出表A中有的一条数据,但是表B中没有的。或者表B中有的,表A中没有的。或者表A和表B同时都存在的一条数据,但是里面的某一些字段不一样。
4、两张报表的格式可能不一样,有可能为csv,xls,xlsx。两张报表的列数也是不固定的(这两张报表可以是任意的两张报表)
5、将比对结果再汇总到一张excel中(格式没有要求,我这里默认的是xls)
6、主键可能为复合主键,比对的报表,可能需要一次比对多组报表(由于这个需求,是今天才加上的,所以目前代码还处理这个问题,当然会很快加上)
思路一:
1、采用二维数组为主要的数据结构。因为,报表的列数不确定,所以不能构造对象,采用下标来控制每一列
2、将A表中的第一行的主键,然后搜索表B的主键,如果没搜到记下来,如果搜到了,比较所配置的列看是否相同,如果不同记下来,再反搜,表B中的主键来搜素表A,如果表B中有的,表A中没有的,记下来。
将记下来的数据重组,再导出excel。
效率:两张表都是30多列,52行,大概一秒左右比对完导出到excel中。
思路二
1、主要采用了循环加map的方式,再比较是否有相等行的时候,直接用,表A的mapA.get(mapB.get("key"))如果数据不为空,说明在表A中有数据和表B匹配,这里的get有效的减少了一次循环。利用了map.get的方法速度更快。其他的。但是主要逻辑,还是如思路相同
接下来贴出,处理这个需求的主要代码。贴出代码的目的,主要是希望各位网友看到后,能够给指点一二,我这代码,肯定还需要优化,重构。或者说换思路。当然你有什么想法,通过评论,或者邮件告诉我。谢谢
ReadCSVExcel方法
import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; import au.com.bytecode.opencsv.CSVReader; import com.qly.report.operate.facade.IReadExcel; public class ReadCsvImpl implements IReadExcel{ static String qlyStringArr[][] = new String[1000][1000]; static String otherStringArr[][] = new String[1000][1000]; static Map<String,Integer > qlycontent = new HashMap<String,Integer >(); static Map<String,Integer > othercontent = new HashMap<String,Integer >(); @Override public Map<String, Object> readExcel(String path, String flag) { CSVReader reader = null; // 取特定列放到集合 try { InputStream ins = new FileInputStream(new File(path)); InputStreamReader in = new InputStreamReader(ins, "gbk"); reader = new CSVReader(in); int len = reader.readNext().length; String nextline[]; int counter = 0; // 将不同的来源的csv文件分别存放到不同的二维数组中 if ("qly".equals(flag)) { Map<String, Object> qlyMap = new HashMap<String, Object>(); while ((nextline = reader.readNext()) != null) { for (int i = 0; i < len; i++) { qlyStringArr[counter][i] = nextline[i]; } counter++; } qlycontent.put("colNum", len); qlycontent.put("rowNum", counter); qlyMap.put("qlyStringArr", qlyStringArr); qlyMap.put("qlycontent", qlycontent); return qlyMap; } if ("other".equals(flag)) { Map<String, Object> otherMap = new HashMap<String, Object>(); while ((nextline = reader.readNext()) != null) { for (int i = 0; i < len; i++) { otherStringArr[counter][i] = nextline[i]; } counter++; } othercontent.put("colNum", len); othercontent.put("rowNum", counter); otherMap.put("othercontent", othercontent); otherMap.put("otherStringArr", otherStringArr); return otherMap; } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } return null; } }
 
ReadXlsExcel 方法
import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.text.DecimalFormat; import java.util.HashMap; import java.util.Map; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFRow; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import com.qly.report.operate.facade.IReadExcel; import com.qly.report.util.ReportUtil; public class ReadXlsImpl implements IReadExcel{ public static HSSFWorkbook wb = null; public static HSSFSheet hssfSheet =null; public static HSSFRow hssfRow = null; public static XSSFWorkbook xb = null; public static XSSFSheet xssfSheet =null; public static XSSFRow xssfRow =null; public static String qlyStringArr[][] = new String[1000][1000]; public static String otherStringArr[][] = new String[1000][1000]; static Map<String,Integer > qlycontent = new HashMap<String,Integer >(); static Map<String,Integer > othercontent = new HashMap<String,Integer >(); @SuppressWarnings({ "deprecation" }) @Override public Map<String ,Object> readExcel(String path, String flag) { int counter = 0; try { InputStream is = new FileInputStream(new File(path)); wb = new HSSFWorkbook(is); hssfSheet = wb.getSheetAt(0); // 得到总行数 int rowNum = hssfSheet.getLastRowNum(); hssfRow = hssfSheet.getRow(1); int colNum = hssfRow.getPhysicalNumberOfCells(); // 正文内容应该从第二行开始,第一行为表头内容 if("qly".equals(flag)){ Map<String,Object>qlyMap = new HashMap<String, Object>(); for (int i = 1; i < rowNum; i++) { hssfRow = hssfSheet.getRow(i); counter = 0; while (counter < colNum) { qlyStringArr[i][counter] = get2003StringCellValue( hssfRow.getCell((short)counter)).trim(); counter++; } } qlycontent.put("colNum", counter); qlycontent.put("rowNum", rowNum); qlyMap.put("qlyStringArr", qlyStringArr); qlyMap.put("qlycontent", qlycontent); return qlyMap; } if("other".equals(flag)){ Map<String,Object>otherMap = new HashMap<String, Object>(); for (int i =1; i < rowNum; i++) { hssfRow = hssfSheet.getRow(i); counter = 0; while (counter < colNum) { otherStringArr[i][counter] = get2003StringCellValue(hssfRow.getCell((short) counter)).trim(); counter++; } } othercontent.put("colNum", counter); othercontent.put("rowNum", rowNum); otherMap.put("othercontent", othercontent); otherMap.put("otherStringArr", otherStringArr); return otherMap; } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } private static String get2003StringCellValue(HSSFCell cell) { String strCell = ""; if (null == cell) { return ""; } switch (cell.getCellType()) { case HSSFCell.CELL_TYPE_STRING: strCell = cell.getStringCellValue(); break; case HSSFCell.CELL_TYPE_NUMERIC: //使用DecimalFormat类对科学计数法格式的数字进行格式化 DecimalFormat df = new DecimalFormat("#"); String str = String.valueOf(cell.getNumericCellValue()); if(ReportUtil.isNumber(str)){ strCell = df.format(cell.getNumericCellValue()); }else{ strCell = str; } break; case HSSFCell.CELL_TYPE_BOOLEAN: strCell = String.valueOf(cell.getBooleanCellValue()); break; case HSSFCell.CELL_TYPE_BLANK: strCell = ""; break; default: strCell = ""; break; } if (strCell.equals("") || null == strCell) { return ""; } return strCell; } }
 
ReadXlsxExcel方法
import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.text.DecimalFormat; import java.util.HashMap; import java.util.Map; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFCell; import org.apache.poi.xssf.usermodel.XSSFRow; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import com.qly.report.operate.facade.IReadExcel; import com.qly.report.util.ReportUtil; public class ReadXlsxImpl implements IReadExcel { public static HSSFWorkbook wb = null; public static HSSFSheet hssfSheet =null; public static HSSFRow hssfRow = null; public static XSSFWorkbook xb = null; public static XSSFSheet xssfSheet =null; public static XSSFRow xssfRow =null; public static String qlyStringArr[][] = new String[1000][1000]; public static String otherStringArr[][] = new String[1000][1000]; static Map<String,Integer > qlycontent = new HashMap<String,Integer >(); static Map<String,Integer > othercontent = new HashMap<String,Integer >(); @Override public Map<String,Object> readExcel(String path, String flag) { int counter = 0; try { InputStream is = new FileInputStream(new File(path)); xb = new XSSFWorkbook(is); xssfSheet = xb.getSheetAt(0); // 得到总行数 int rowNum = xssfSheet.getLastRowNum(); xssfRow = xssfSheet.getRow(1); int colNum = xssfRow.getPhysicalNumberOfCells(); // 正文内容应该从第二行开始,第一行为表头内容 if("qly".equals(flag)){ Map<String,Object>qlyMap = new HashMap<String, Object>(); for (int i = 1; i < rowNum; i++) { xssfRow = xssfSheet.getRow(i); counter = 0; while (counter < colNum) { qlyStringArr[i][counter] = get2007StringCellValue( xssfRow.getCell((short) counter)).trim(); counter++; } } qlycontent.put("colNum", counter); qlycontent.put("rowNum", rowNum); qlyMap.put("qlyStringArr", qlyStringArr); qlyMap.put("qlycontent", qlycontent); return qlyMap; } if("other".equals(flag)){ Map<String,Object>otherMap = new HashMap<String, Object>(); for (int i = 1; i < rowNum; i++) { xssfRow = xssfSheet.getRow(i); counter = 0; while (counter < colNum) { otherStringArr[i][counter] = get2007StringCellValue( xssfRow.getCell((short) counter)).trim(); counter++; } } othercontent.put("colNum", counter); othercontent.put("rowNum", rowNum); otherMap.put("othercontent", othercontent); otherMap.put("otherStringArr", otherStringArr); return otherMap; } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } private static String get2007StringCellValue(XSSFCell cell) { String strCell = ""; if (null == cell) { return ""; } switch (cell.getCellType()) { case XSSFCell.CELL_TYPE_STRING: strCell = cell.getStringCellValue(); break; case XSSFCell.CELL_TYPE_NUMERIC: //使用DecimalFormat类对科学计数法格式的数字进行格式化 DecimalFormat df = new DecimalFormat("#"); String str = String.valueOf(cell.getNumericCellValue()); if(ReportUtil.isNumber(str)){ strCell = df.format(cell.getNumericCellValue()); }else{ strCell = str; } break; case XSSFCell.CELL_TYPE_BOOLEAN: strCell = String.valueOf(cell.getBooleanCellValue()); break; case XSSFCell.CELL_TYPE_BLANK: strCell = ""; break; default: strCell = ""; break; } if (strCell.equals("") || null == strCell) { return ""; } return strCell; } }
全部代码在这里,github,请多多指教