JAVA导入多个excel文件,并将有效的数据导出到一个文件中
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
/**
* poi方式导入多个excel文件,并将有效的数据导出到一个文件中
* usarp数据文件的生成
* @author hyzhang
*
*/
public class ReadExcel_Poi_All {
//配置文件的路径,位置与项目同级
private String configPath=System.getProperty("user.dir")+"/config.xml";
//定义日志文件,位置为与项目同级目录下的log文件夹,名称为“impor_log_”+当前的时间
public static final LogWriter logger=LogWriter.getLogWriter(System.getProperty("user.dir")+"/log/impor_log_"
+new SimpleDateFormat( "yyyyMMddHHmmss" ).format(new Date())+".log");
//配置信息对象
private ConfigObj config=null;
public ReadExcel_Poi_All() {
}
/**
* 主函数
* @param args
* @throws Exception
*/
public static void main(String args[]) throws Exception {
//读取配置文件信息
ReadExcel_Poi_All read = new ReadExcel_Poi_All();
read.readXML();
ConfigObj config=read.config;
ReadExcel readexcel=new ReadExcel();
String exportPath=null;//文件导出路径
try {
//读取文件夹下的的excel文件
File root = new File((config.getImport_location()).replaceAll("\\\\","/"));
File[] files = root.listFiles();
if(files.length!=Integer.parseInt(config.getImport_count())){
logger.log("文件数量不符合配置要求,配置数量:"+config.getImport_count()+",实际数量:"+files.length);
throw new Exception("文件数量不符合配置要求");
}
FileWriter fw = null;//文件输出
String period=null;//文件日期
//遍历每个excel文件
for(File file:files){
String filename=file.getName();
//判断文件的格式是否正确
if(!filename.endsWith("xls")&&!filename.endsWith(".xlsx")){
logger.log("文件:"+filename+"不是excel文件,请检查");
logger.log("跳过文件:"+filename+"导入,继续下一个文件!");
// throw new Exception("文件"+filename+"类型不正确");
}
InputStream is = new FileInputStream(file);
HSSFWorkbook workbook = new HSSFWorkbook(is);// 得到工作薄
int iSheetNum = workbook.getNumberOfSheets();
//支持多个sheet
for (int numSheets = 0; numSheets < iSheetNum; numSheets++) {
if (null != workbook.getSheetAt(numSheets)) {
HSSFSheet st = workbook.getSheetAt(numSheets);// 获得一个sheet
//sheet的名称包含着日期信息
String sheetName=workbook.getSheetName(numSheets);
String now_period=null;
try {//工作表中sheet名称不是标准的日期信息,则此sheet数据不需要导入则遍历下一个sheet
now_period="20"+sheetName.substring(3,5)+sheetName.substring(1,3);//根据sheet名称获取工作表
} catch (Exception e) {
logger.log("工作簿:" +file.getName()+"中第"+(numSheets+1)+"个工作表"+sheetName+"信息不需要导入!");
continue;
}
//读取的首个文件的首个sheet,设置导出文件流信息
if(fw==null){
period=now_period;
//导出的文件信息,文件路径(字符转换正反斜杠问题)+文件文件名+文件类型
exportPath=(config.getExport_location()).replaceAll("\\\\","/")+"/"+config.getExport_name()+period+"."+config.getExport_type();
logger.log("文件导出路径:"+exportPath);
fw = new FileWriter(exportPath);
//记录表头信息
fw.write(config.getExportTitle()+"\r\n");
fw.flush();
}
//判断文件数据是否为同一批次
if(!now_period.equals(period)){
logger.log("文件数据不是同一批!");
throw new Exception("文件数据不是同一批!");
}
logger.log("开始导入工作簿:" +file.getName()+"中第"+(numSheets+1)+"个工作表"+sheetName+"信息");
if(!readexcel.importObjFromSheet(st,fw,config,period)){//读取文件有效信息写入导出的文件
logger.log("工作簿:" +file.getName()+"中第"+(numSheets+1)+"个工作表"+sheetName+"信息执行导入出错!");
};
logger.log("成功导入工作簿:" +file.getName()+"中第"+(numSheets+1)+"个工作表"+sheetName+"信息");
}
}
}
fw.close();
logger.log("全部"+config.getImport_count()+"个文件读取成功");
} catch (Exception e) {
logger.log(e.getMessage());
try {//出现异常信息则,删除已经生成的导出文件
File export=new File(exportPath);
export.delete();
logger.log("导入文件过程中出错,将导出的文件信息删除!");
} catch (Exception e1) {
}
e.printStackTrace();
}
}
/**
* 执行参数初始化
* @throws Exception
*/
public void readXML() throws Exception{
try {
logger.log("开始读取配置文件");
this.config=new ConfigObj();
SAXReader reader = new SAXReader();
Document document = reader.read(new File(this.configPath));
Element rootElm = document.getRootElement(); //读取XML获取根节点
Element importElm = rootElm.element("import");
Element exportElm = rootElm.element("export");
String Import_location=importElm.attributeValue("location");
if(Import_location.isEmpty()){
logger.log("请设置需要导入文件有效的的文件夹信息");
throw new Exception("请设置需要导入文件有效的的文件夹信息");
}
logger.log("配置信息:导入文件的位置:"+Import_location);
String Import_count=importElm.attributeValue("count");
logger.log("配置信息:导入文件的数量:"+Import_count);
String Import_strart=importElm.attributeValue("start");
logger.log("配置信息:导入文件的有效数据起始字符:"+Import_strart);
String Import_end=importElm.attributeValue("end");
logger.log("配置信息:导入文件的有效数据结束字符:"+Import_end);
String Import_audit3len=importElm.attributeValue("audit3len");
logger.log("配置信息:导入文件的audit列值是否限制为长度3:"+Import_audit3len);
List propertys=importElm.elements("property");
logger.log("配置信息:开始配置有效数据的列名与内存对象的对应关系");
HashMap<String,Object> fieldsHashMap = new HashMap<String,Object>();
int i=0;
StringBuffer exportTitle = new StringBuffer();
exportTitle.append("mnt,");//将日期信息放在到表头的第一列
for (Iterator it = propertys.iterator(); it.hasNext();) {
Element property = (Element) it.next();
String name=property.attributeValue("name");
String out_name=property.attributeValue("out_name");
fieldsHashMap.put(name, ++i);
exportTitle.append(out_name).append(",");
logger.log("配置信息:excel的表头信息与数据对象对应关系:"+name+"<==>"+i);
}
logger.log("配置信息:文件中有效数据列数:"+i);
if(i>13){
logger.log("配置信息:有效属性列不能大于13,否则将有数据不完全导出");
throw new Exception("有效属性列不能大于13,否则将有数据不完全导出");
}
String export_location=exportElm.attributeValue("location");
logger.log("配置信息:文件导出位置:"+export_location);
String export_type=exportElm.attributeValue("type");
logger.log("配置信息:文件导出类型:"+export_type);
String export_name=exportElm.attributeValue("name");
logger.log("配置信息:文件导出名称:"+export_name);
config.setImport_count(Import_count);
config.setImport_location(Import_location);
config.setStart_str(Import_strart);
config.setEnd_str(Import_end);
config.setImport_audit3len(Import_audit3len);
config.setExport_location(export_location);
config.setExport_type(export_type);
config.setExport_name(export_name);
config.setFieldsHashMap(fieldsHashMap);
config.setExportTitle(exportTitle.deleteCharAt(exportTitle.length()-1).toString());
logger.log("配置文件读取成功");
} catch (DocumentException e) {
logger.log("配置文件读取出错,请检查文件的位置及格式是否正确");
logger.log(e);
e.printStackTrace();
}
}
}
/**
* 配置文件类
* @author hyzhang
*/
class ConfigObj{
private String import_location=null;//文件的导入路径
private String import_count=null;//文件的导入数量
private String start_str=null;//有效数据标题开始列值
private String end_str=null;//文件的结束行下一行的列值
private String export_location=null;//文件的导出路径
private String export_type=null;//文件的导出类型
private String export_name=null;//文件的导出名称
private String import_audit3len=null;//文件导入audit长度限制
private HashMap<String,Object> FieldsHashMap=null;//字段映射
private String exportTitle=null;//导出文件的title
public ConfigObj() {
super();
}
public String getImport_location() {
return import_location;
}
public void setImport_location(String import_location) {
this.import_location = import_location;
}
public String getImport_count() {
return import_count;
}
public void setImport_count(String import_count) {
this.import_count = import_count;
}
public String getExport_location() {
return export_location;
}
public void setExport_location(String export_location) {
this.export_location = export_location;
}
public String getExport_type() {
return export_type;
}
public void setExport_type(String export_type) {
this.export_type = export_type;
}
public String getExport_name() {
return export_name;
}
public void setExport_name(String export_name) {
this.export_name = export_name;
}
public String getStart_str() {
return start_str;
}
public void setStart_str(String start_str) {
this.start_str = start_str;
}
public String getEnd_str() {
return end_str;
}
public void setEnd_str(String end_str) {
this.end_str = end_str;
}
public HashMap<String, Object> getFieldsHashMap() {
return FieldsHashMap;
}
public void setFieldsHashMap(HashMap<String, Object> fieldsHashMap) {
FieldsHashMap = fieldsHashMap;
}
public String getExportTitle() {
return exportTitle;
}
public void setExportTitle(String exportTitle) {
this.exportTitle = exportTitle;
}
public String getImport_audit3len() {
return import_audit3len;
}
public void setImport_audit3len(String import_audit3len) {
this.import_audit3len = import_audit3len;
}
}
/**
* 文件处理类
* @author hyzhang
*
*/
class ReadExcel{
//日志对象
private LogWriter logger=ReadExcel_Poi_All.logger;
/**
* 从一个workSheet中读取需要记录信息
*
* @param _importSheet 导入文件的一个sheet
* @param fw 导出文件流
* @return
*/
public boolean importObjFromSheet(HSSFSheet _importSheet,FileWriter fw,ConfigObj config,String priod) {
HashMap<String,Object> FieldsHashMap=config.getFieldsHashMap();
String startStr=config.getStart_str();
String endStr=config.getEnd_str();
String audit3len=config.getImport_audit3len();
int nSheetCount = _importSheet.getLastRowNum();//总的行数
if (nSheetCount <= 1) {
logger.log("工作表不包含信息!请检查工作表信息");
return false;// 用户身份sheet的第一行是字段
}
// 获取excel与内存对象的映射关系
// HashMap<String,Object> FieldsHashMap = getExcelFieldToUserFieldMap();
HashMap<String,Object> columnToFieldMap=new HashMap<String,Object>();//列号与内存用户的字段映射关系
boolean start=false;//数据开始的标志
boolean end=false;//数据结束的标志
short startcell=0;//有效数据开始的列
// 1.遍历行
for (int i = 0; i < nSheetCount; i++) {
// 获得一行的所有单元格
HSSFRow row = _importSheet.getRow(i);
ImportObj aImportObj = new ImportObj();
boolean bNeedSaveRow = false;// 是否需要保存该单元格
// 遍历单元格内容
for (short j = startcell; j < row.getLastCellNum(); j++) {
HSSFCell aCell = row.getCell(j);
// 获得单元格内容
String cellContent = String.valueOf(aCell);
// 如果单元格没有内容,则忽略
if (cellContent == null || "".equals(cellContent)) {
continue;
}
//判断是否结束结束则不再读取
if(endStr.equals(cellContent)){
logger.log("有效数据的结束行:"+(i+1));
end=true;
break;//此行不记录
}
else if(start&&!end){
// 根据列号匹配出该列的名称
Object oFieldNameInDB = columnToFieldMap.get(String.valueOf(j));
if (oFieldNameInDB == null || "".equals(oFieldNameInDB))
continue;
// 赋值,根据列名设置内存对象的属性值信息
setProperty(aImportObj, (Integer)oFieldNameInDB, cellContent);
bNeedSaveRow = true;
}//初始数据,获取Excel表头与内存对象映射关系
else if(startStr.equals(cellContent)){//数据的开始行,头部信息
start=true;
startcell=j;//设置数据的初始列
logger.log("有效数据的初始行:"+(i+1));
// 获取excel列号与内存用户的字段映射关系
columnToFieldMap = getColumnToField(_importSheet, FieldsHashMap,i);
break;//此行数据不继续读取
}
}
if(end)
break;
if (!bNeedSaveRow) {
continue;//此行无数据需要保存
}
// 处理一行的用户信息数据
logger.log("开始记录第"+(i+1)+"行的数据信息");
aImportObj.setPriod(priod);//设置实体的日期信息,日期是由sheet的名称获取
doRealSave(aImportObj,fw,audit3len);
logger.log("完成记录第"+(i+1)+"行的数据信息");
}
return true;
}
/**
* 根据内存数据对象实现数据的真正导入逻辑
* @param _importUser
* 从Excel中读取到的内存数据对象
* @return
*/
private boolean doRealSave(ImportObj _importObj,FileWriter fw,String audit3len) {
try {
//判断audit是否需要截取3个字符
if("Y".equals(audit3len.toUpperCase())){
_importObj.setA(_importObj.getA().substring(0,3));//重新设置audit信息
}
//specialty的为空或者为END的处理
if(_importObj.getB()==null){
_importObj.setB("GEN");
}
//Spec Code为空的处理,解决CHC中为空的问题
if(_importObj.getC()==null){
_importObj.setC("9");
}
//设置Speciality的值为首字母前三位
_importObj.setB(_importObj.getB().substring(0,3).toUpperCase());
//将某些excel特殊数据类型的列做了处理
DecimalFormat df=new DecimalFormat("0.000");
_importObj.setF(df.format(Double.valueOf(_importObj.getF())));
StringBuffer str = new StringBuffer();//记录每行的信息
str.append(_importObj.getPriod()).append(",") //mnt
.append(_importObj.getA()).append(",") //audit
.append("END".equals(_importObj.getB())?"GEN":_importObj.getB()).append(",") //spec,存储简写值
.append(_importObj.getC().replace(".0", "")).append(",") //speccode
.append(_importObj.getD().replace(".0", "")).append(",") //bsc12
.append("0.000".equals(_importObj.getE())?"0":sideTrim(Double.valueOf(_importObj.getE()).toString(),".0")).append(",") //pf
.append("0.000".equals(_importObj.getF())?"0":sideTrim(Double.valueOf(_importObj.getF()).toString(),".0")).append("\r\n"); //af
// .append(_importObj.getG()).append(",")
// .append(_importObj.getH()).append(",")
// .append(_importObj.getI()).append(",")
// .append(_importObj.getJ()).append(",")
// .append(_importObj.getK()).append(",")
// .append(_importObj.getL()).append(",")
// .append(_importObj.getM()).append("\r\n");
fw.write(str.toString());
fw.flush();
} catch (IOException e) {
logger.log("记录数据出错!");
e.printStackTrace();
}catch(Exception e1){
logger.log("记录数据出错!");
e1.printStackTrace();
}
return true;
}
/**
* 向一个内存数据对象设置一个属性
*
* @param _importUser
* @param _sName
* @param _sValue
*/
private ImportObj setProperty(ImportObj _importobj, int _sName,
String _sValue) {
switch (_sName) {
case 1:
_importobj.setA(_sValue);
break;
case 2:
_importobj.setB(_sValue);
break;
case 3:
_importobj.setC(_sValue);
break;
case 4:
_importobj.setD(_sValue);
break;
case 5:
_importobj.setE(_sValue);
break;
case 6:
_importobj.setF(_sValue);
break;
case 7:
_importobj.setG(_sValue);
break;
case 8:
_importobj.setH(_sValue);
break;
case 9:
_importobj.setI(_sValue);
break;
case 10:
_importobj.setJ(_sValue);
break;
case 11:
_importobj.setK(_sValue);
break;
case 12:
_importobj.setL(_sValue);
break;
case 13:
_importobj.setM(_sValue);
break;
default:
break;
}
return _importobj;
}
/**
* 获取excel表中的列号与内存对象映射关系
* @param _sheet
* @param FieldsHashMap
* excel字段与内存数据对象字段的映射关系
* @param row 有效数据起始行
* @return
*/
private HashMap<String,Object> getColumnToField(HSSFSheet _sheet, HashMap<String,Object> FieldsHashMap,int startRow)
{
//获取有效的行信息
HashMap<String,Object> ColumnToFieldMap = new HashMap<String,Object>();
// 获得有效数据的第一行数据,为表头信息
HSSFRow row = _sheet.getRow(startRow);
for (short j = 0; j < row.getLastCellNum(); j++) {
//获取表头的列内容
HSSFCell aCell = row.getCell(j);
// 获得单元格内容
String content =String.valueOf(aCell);
if (content == null || "".equals(content))
continue;
// 判断当前单元格内容是否是需要记录信息的基本字段
//特殊处理CHC的BSC值的处理,文件的属性值分为“Strat\Strta\Strata”
if(content.equals("Stata")||content.equals("Strata"))
content="Strat";
Object oMapField = FieldsHashMap.get(content);
if (oMapField == null || "".equals(oMapField))
continue;
// 列号与字段映射的hashMap添加记录
ColumnToFieldMap.put(String.valueOf(j), oMapField);
}
return ColumnToFieldMap;
}
/**
* 去掉字符串结尾的特殊字符
* @param stream 需要处理的字符串
* @param trimstr 去掉的字符串
* @return 处理后的字符串
*/
private String sideTrim(String stream, String trimstr) {
// null或者空字符串的时候不处理
if (stream == null || stream.length() == 0 || trimstr == null || trimstr.length() == 0) {
return stream;
}
// 结束位置
int epos = 0;
// 正规表达式
String regpattern = "[" + trimstr + "]*+";
Pattern pattern = Pattern.compile(regpattern, Pattern.CASE_INSENSITIVE);
// 去掉结尾的指定字符
StringBuffer buffer = new StringBuffer(stream).reverse();
Matcher matcher = pattern.matcher(buffer);
if (matcher.lookingAt()) {
epos = matcher.end();
stream = new StringBuffer(buffer.substring(epos)).reverse().toString();
}
// 返回处理后的字符串
return stream;
}
/**
* Excel导入数据对象的内存类
* @author hyzhang
*
*/
public class ImportObj {
public ImportObj() {
super();
}
private String a = null;
private String b= null;
private String c = null;
private String d = null;
private String e = null;
private String f = null;
private String g = null;
private String h = null;
private String i = null;
private String j = null;
private String k = null;
private String l = null;
private String m = null;
private String priod=null;
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
public String getC() {
return c;
}
public void setC(String c) {
this.c = c;
}
public String getD() {
return d;
}
public void setD(String d) {
this.d = d;
}
public String getE() {
if(e==null)
e="0";
return e;
}
public void setE(String e) {
this.e = e;
}
public String getF() {
if(f==null)
f="0";
return f;
}
public void setF(String f) {
this.f = f;
}
public String getG() {
return g;
}
public void setG(String g) {
this.g = g;
}
public String getH() {
return h;
}
public void setH(String h) {
this.h = h;
}
public String getI() {
return i;
}
public void setI(String i) {
this.i = i;
}
public String getJ() {
return j;
}
public void setJ(String j) {
this.j = j;
}
public String getK() {
return k;
}
public void setK(String k) {
this.k = k;
}
public String getL() {
return l;
}
public void setL(String l) {
this.l = l;
}
public String getM() {
return m;
}
public void setM(String m) {
this.m = m;
}
public String getPriod() {
return priod;
}
public void setPriod(String priod) {
this.priod = priod;
}
}
}
/**
* 日志类信息
* @author hyzhang
*
*/
class LogWriter {
// 日志的配置文件
public static final String LOG_CONFIGFILE_NAME = "log.properties";
// 日志文件名在配置文件中的标签
public static final String LOGFILE_TAG_NAME = "logfile";
// 默认的日志文件的路径和文件名称
private final String DEFAULT_LOG_FILE_NAME = "./logtext.log";
// 该类的唯一的实例
private static LogWriter logWriter;
// 文件输出流
private PrintWriter writer;
// 日志文件名
private String logFileName;
/**
* 默认构造函数
*/
private LogWriter() {
this.init();
}
private LogWriter(String fileName) {
this.logFileName = fileName;
this.init();
}
/**
* 获取LogWriter的唯一实例。
*
* @return
* @throws LogException
*/
public synchronized static LogWriter getLogWriter() {
if (logWriter == null) {
logWriter = new LogWriter();
}
return logWriter;
}
public synchronized static LogWriter getLogWriter(String logFileName)
{
if (logWriter == null) {
logWriter = new LogWriter(logFileName);
}
return logWriter;
}
/**
* 往日志文件中写一条日志信息 为了防止多线程同时操作(写)日志文件,造成文件”死锁”。使用synchronized关键字
*
* @param logMsg
* 日志消息
*/
public synchronized void log(String logMsg) {
this.writer.println(new java.util.Date() + ": " + logMsg);
}
/**
* 往日志文件中写一条异常信息 使用synchronized关键字。
* @param ex
* 待写入的异常
*/
public synchronized void log(Exception ex) {
writer.println(new java.util.Date() + ": ");
ex.printStackTrace(writer);
}
/**
* 初始化LogWriter
*
* @throws LogException
*/
private void init() {
// 如果用户没有在参数中指定日志文件名,则从配置文件中获取。
if (this.logFileName == null) {
this.logFileName = this.getLogFileNameFromConfigFile();
// 如果配置文件不存在或者也没有指定日志文件名,则用默认的日志文件名。
if (this.logFileName == null) {
this.logFileName = DEFAULT_LOG_FILE_NAME;
}
}
File logFile = new File(this.logFileName);
try {
// 其中的FileWriter()中的第二个参数的含义是:是否在文件中追加内容
// PrintWriter()中的第二个参数的含义是:自动将数据flush到文件中
writer = new PrintWriter(new FileWriter(logFile, true), true);
System.out.println("日志文件的位置:" + logFile.getAbsolutePath());
} catch (IOException ex) {
String errmsg = "无法打开日志文件:" + logFile.getAbsolutePath();
System.out.println(errmsg);
}
}
/**
* 从配置文件中取日志文件名
*
* @return
*/
private String getLogFileNameFromConfigFile() {
try {
Properties pro = new Properties();
// 在类的当前位置,查找属性配置文件log.properties
InputStream fin = getClass().getResourceAsStream(
LOG_CONFIGFILE_NAME);
if (fin != null) {
pro.load(fin);// 载入配置文件
fin.close();
return pro.getProperty(LOGFILE_TAG_NAME);
} else {
System.err.println("无法打开属性配置文件: log.properties");
}
} catch (IOException ex) {
System.err.println("无法打开属性配置文件: log.properties");
}
return null;
}
// 关闭LogWriter
public void close() {
logWriter = null;
if (writer != null) {
writer.close();
}
}
}