这几天由于工作需要,需要做一个报表比对工具(找出两张报表的差异)。需求如下
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; }
}
CompareExcel方法,比较算法在这里
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;import com.qly.report.operate.facade.ICompareExcel;
import com.qly.report.util.ReportUtil;
/**
-
by guop 2013-7-12 上午 9:11:06
-
比较 excel
*/
public class CompareExcelImpl implements ICompareExcel{@Override
public Map<String ,Object> compareExcel(String [][] qlyString, String [][] otherString,
int[] qlycolumn, int[] othercolumn,
Map<String,Integer> qlycontent, Map<String,Integer> othercontent,
int qlyflag, int otherflag, int qlystartRow, int otherstartRow,
String outReportPath) {// 761报表的行数 int qlyRowNum = qlycontent.get("rowNum"); // 761报表的列数 int otherRowNum = othercontent.get("rowNum"); List<Map<String, Integer>> listErrorStr = new ArrayList<Map<String, Integer>>(); // 在这里比较下,用a表的标记字段扫描b表从1开始,0为表头 for (int i = qlystartRow; i < qlyRowNum; i++) { boolean boolflag = false; boolean boolother = true; Map<String, Integer> errorMap = new HashMap<String, Integer>(); for (int j = otherstartRow; j < otherRowNum; j++) { // 按照配置的标记列,如761中的票号,和腾邦的票号 // 表a中的第一行某字段,遍历表b中的行中的这一字段,看是否相同0 if (ReportUtil.handleSpecialCharacter(qlyString[i][qlyflag].trim()).equals(ReportUtil.handleSpecialCharacter(otherString[j][otherflag].trim()))) { boolother = false; int rowother = j; // 在寻找到b表中,有相同的字段后,比较其他字段是否相同 for (int a1 = 0; a1 < qlycolumn.length;a1++) { if(null == qlyString[i][qlycolumn[a1]] || null == otherString[rowother][othercolumn[a1]]){ break; } // 当a表和b表中的 票面号相同,比较里面的规定的字段的值是否相同 if (!ReportUtil.handleSpecialCharacter(qlyString[i][qlycolumn[a1]].trim()).equals(ReportUtil.handleSpecialCharacter(otherString[rowother][othercolumn[a1]].trim()))) { errorMap.put("qlylinenumber", i); errorMap.put("otherlinenumber", rowother); listErrorStr.add(errorMap); boolflag = true; break; } } if (boolflag) { break; } } } if (boolother) { errorMap.put("qlylinenumber", i); listErrorStr.add(errorMap); } } //用b表扫描a表的某一个字段 // 在这里比较下,用a表的标记字段扫描b表 for (int i = otherstartRow; i < otherRowNum; i++) { boolean boolother = true; Map<String, Integer> errorMap = new HashMap<String, Integer>(); for (int j = qlystartRow; j < qlyRowNum; j++) { // 按照配置的标记列,如761中的票号,和腾邦的票号 // 表a中的第一行某字段,遍历表b中的行中的这一字段,看是否相同0 if (ReportUtil.handleSpecialCharacter(qlyString[j][qlyflag].trim()).equals(ReportUtil.handleSpecialCharacter(otherString[i][otherflag].trim()))) { boolother = false; // 在寻找到b表中,有相同的字段后,比较其他字段是否相同 } } if (boolother) { errorMap.put("otherlinenumber", i); listErrorStr.add(errorMap); } } Map<String,Object> compareMap = new HashMap<String, Object>(); compareMap.put("listErrorStr", listErrorStr);
return compareMap;
}
}
全部代码在这里,github,请多多指教
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于