使用阻塞式队列处理大数据

转自:http://blog.csdn.net/lifetragedy/article/details/50593588


前言

我们都知道,JAVA对于文本文件在读时是独占的,即使可以用多线程去读也涉及到一个POS(定位读)的问题,这在设计框架上会带来许多的复杂性,同时也带来代码上的不可维护性以及会经常出一些千奇百怪的错误(多线程程序由其如此)。


传统阻塞式做法的敝病

  • 特点:多线程,阻塞式导入
  • 缺点:阻塞式,导入速度慢,线程状态无法精确记录,速度慢内存开销大

优秀的做法

  • 多线程
  • 非阻塞式
  • 内存开销恒定
  • 线程可以自由增加

我们将采用的做法

在数据提取的设计时基于以下几个指标考虑:

1)内存占用数始终必须恒定值

2)使用多线程非阻塞式算法,即不加线程锁机制

3) 尽可能少的占用数据库的打开游标数和CPU效率

4) 保证数据读和写的速度




在此,我们将利用阻塞队列+多线程来加快我们的大数据文件的处理速度即使用
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. BlockingQueue<Map> queue = new ArrayBlockingQueue<Map>(TASK_LIST_SIZE)  

为什么要使用BlockingQueue

  • 它会自动阻塞大于Queue Size的写入动作
  • 栈的机制,get一个队列中的item,相应的Queue中的item数就会减少一个
  • 因为有栈的机制,因此我们可以使用Queue中的这个机制无需多写一个Daemon线程来监控我们的所有的items是不是全取完了然后结束线程,更有甚者我看到过许多程序员写一个While循环,循环直至所有的item取完哪怕有很大一部分是在“空转”也在所不惜。
  • 读/处理完全相分离,读完后也一定处理完了

核心代码

读文件代码

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public void run() {  
  2.     try {  
  3.         enumerate(super.fileName, super.colNames);  
  4.     } catch (Exception e) {  
  5.         logger.error("read txtFileName error, parse excel quit because :"  
  6.                 + e.getMessage(), e);  
  7.         try {  
  8.             Thread.interrupted();  
  9.         } catch (Exception ee) {  
  10.         }  
  11.         } finally {  
  12.         try {  
  13.             queue.put(DUMMY);  
  14.                 // BatchTaskQueue.getInstance().taskList.put(DUMMY);  
  15.         } catch (Exception ex) {  
  16.         }  
  17.     }  
  18.   
  19. }  
这边需要注意的点有2处:
  • enumerate就是读,在这段代码下还有一个具体的enumerate的实现,它是顶部递归直到把一个文件内所有的ITEM全部queue.put到队列中去
  • 为什么finally块中要有一个queue.put(DUMMY)哈,一般程序员看到这个语句或者碰到一个什么DUMMY的最头疼了,这是什么个玩意的哈?
DUMMY在我们这边是这样定义的
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. protected static Map DUMMY = new HashMap();  
它代表一个“空”的标志,比如说一个文件 有50万条记录,那么我们的queue中其实会放入50万零1条记录,最后那个1条记录就是这个DUMMY,它告诉另一个take即真正处理导出的线程(可能是一堆的线程,因为我们用的是多线程处理)你已经处理到没有记录可以“再让你处理了“,因此呢。。。因此你得结束了。。。所以我在这边说读完文件 ,正好处理完指的就是这个,因此我们在处理线程(子线程)中对这个DUMMY是如下处理的:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. while (!done) {  
  2.     Map data = (Map) queue.take();  
  3.     if (data == EnumerationEnginee.DUMMY) {  
  4.         //no data  
  5.         queue.put(data);  
  6.         done = true;  
  7.     } else {  
  8.         // if (data != null) {  
  9.         for (Iterator it = data.keySet().iterator(); it.hasNext();) {  
  10.             String key = String.valueOf(it.next());  
  11.             System.out.print("import:>>>[" + key + "]  :  ["+ data.get(key) + "]");  
  12.         }  
  13.         System.out.println("\n");                         
  14.     }  
  15. }  

处理Queue中item的代码(多线程)

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public void run() {  
  2.     boolean done = false;  
  3.     try {  
  4.         synchronized (this) {  
  5.             while (!done) {  
  6.                 Map data = (Map) queue.take();  
  7.                 if (data == EnumerationEnginee.DUMMY) {  
  8.                     //no data  
  9.                     queue.put(data);  
  10.                     done = true;  
  11.                 } else {  
  12.                     // if (data != null) {  
  13.                     for (Iterator it = data.keySet().iterator(); it.hasNext();) {  
  14.                         String key = String.valueOf(it.next());  
  15.                         System.out.print("import:>>>[" + key + "]  :  ["+ data.get(key) + "]");  
  16.                     }  
  17.                     System.out.println("\n");                         
  18.                 }  
  19.             }  
  20.         }  
  21.     } catch (Exception e) {  
  22.         logger.error("import file into db error:" + e.getMessage(), e);  
  23.         try {  
  24.             Thread.interrupted();  
  25.         } catch (Exception ie) {  
  26.         }  
  27.         try {  
  28.             queue.put(EnumerationEnginee.DUMMY);  
  29.             done = true;  
  30.         } catch (Exception ex) {  
  31.   
  32.         }  
  33.     } finally {  
  34.         threadSignal.countDown();  
  35.     }  
  36.   
  37. }  

代码解读

一切源于需求,一切源于”业务“场景,这边的业务不是让大家去做业务,而是”idea“。

老习惯,注意下面红色加粗文字,我们就喜欢“ ”,YEAH!

大家知道了一个BlockQueue,OK,这东西的好处在于:

  1. 你可以设一个size=100的Queue,然后把几十万数据往里扔,当扔到100个的时候它会自动帮你阻塞住,然后你可以起一堆的线程去扫这个Queue里的item而且你扫一个(queue.take())一个,queue里实际的item就会自动减少一个,因此一个线程take后你不用担心另一个线程去”重复take”。这样我们的读和handle就可以相分离。
  2. 在多线程扫queue里的item时你要告诉线程,已经到queue的底啦,没东西可取了,你可以停了,因此当所有的handle线程都碰到queue的“底”时,它们就都会自动停止了,因此我说了,基本上可以做到读完文件中的条数,所有的handle线程也正好处理完。
最后:

我们以实际场景出发一般在handle时都是写数据库或者是NOSQL,因此涉及到一个key, value的问题,因此在这边我们往queue里put的是一个Map。

这就是核心设计思路,此处有一个地方需要高度注意:

DUMMY是一个“空”标准,可是你千万不能放一个NULL,因为一旦你放了NULL,在Queue.take, Queue.put时会直接出错,这将打乱整个线程的运行,因此你一定要New一个,如:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <strong><span style="color:#cc0000;">Map DUMMY = new HashMap();</span></strong>  

看,要这样才行。

绝对不要Map DUMMP=null,那就完蛋了。D...D...D...D.E.A.D!


如何对整个多线程的process过程进行计时

请见 BatchImportExec.java中以下这行:



ImportTask.java中



给出完整例子

业务需求


  1. 我们需要一个封装好的方法,传入一个文件,然后用多线程handle这个文件中的行数。
  2. 线程数,队列size可设
  3. 需要有一个计时的功能,即从处理开始到处理结束,这个过程一共耗时多少(不少人在多线程处理任务上的计时很头疼,在例子中一并解决该问题)
  4. 最后这个处理过程能够支持csv, txt, excel, 数据库...bla,bla,bla等多种格式的文件(由于篇幅有限我们在这边只实现 1)对于txt/csv和excel文件的处理 2)给出工厂方法可以便于大家自己去扩展这个FileParser。
  5. 处理大数据的excel文件 ,大家都知道我们无论是使用POI还是JXL都会遇上当EXCEL的行数超过65,535行时,你只要worksheet一下,整个JVM内存直接“爆掉”的经验,那么怎么去更高效更少内存的处理大数据量的EXCEL文件呢?如一个excel含有50万行数据时。。。你怎么处理?在此例子中一并给出解决方案。

主要框架代码

BatchDTO.java

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package batchpoc;  
  2.   
  3. import java.io.Serializable;  
  4. import java.util.ArrayList;  
  5. import java.util.Arrays;  
  6. import java.util.Date;  
  7. import java.util.List;  
  8. import java.util.Map;  
  9.   
  10. public class BatchDTO implements Serializable {  
  11.   
  12.     private String pkBtTaskId = "";  
  13.     private String taskName = "";  
  14.     private String actionType = "";  
  15.     private String taskDesc = "";  
  16.     private String status = "";  
  17.     private String commitedBy = "";  
  18.     private Date commitedTime = null;  
  19.     private String resultLog = "";  
  20.     private String batchId = "";  
  21.     private boolean headSkip = true;  
  22.     private String errorLogPath = "";  
  23.     private String logRootPath = "";  
  24.     private boolean errorFlag = false;  
  25.     private String campId = "";  
  26.     private String[] data = null;  
  27.     private long totalCount = 0;  
  28.   
  29.     @Override  
  30.     public int hashCode() {  
  31.         final int prime = 31;  
  32.         int result = 1;  
  33.         result = prime * result  
  34.                 + ((actionType == null) ? 0 : actionType.hashCode());  
  35.         result = prime * result + ((batchId == null) ? 0 : batchId.hashCode());  
  36.         result = prime * result + ((campId == null) ? 0 : campId.hashCode());  
  37.         result = prime * result  
  38.                 + ((commitedBy == null) ? 0 : commitedBy.hashCode());  
  39.         result = prime * result  
  40.                 + ((commitedTime == null) ? 0 : commitedTime.hashCode());  
  41.         result = prime * result + Arrays.hashCode(data);  
  42.         result = prime * result + (errorFlag ? 1231 : 1237);  
  43.         result = prime * result  
  44.                 + ((errorLogPath == null) ? 0 : errorLogPath.hashCode());  
  45.         result = prime * result + (headSkip ? 1231 : 1237);  
  46.         result = prime * result  
  47.                 + ((logRootPath == null) ? 0 : logRootPath.hashCode());  
  48.         result = prime * result  
  49.                 + ((pkBtTaskId == null) ? 0 : pkBtTaskId.hashCode());  
  50.         result = prime * result  
  51.                 + ((resultLog == null) ? 0 : resultLog.hashCode());  
  52.         result = prime * result + ((status == null) ? 0 : status.hashCode());  
  53.         result = prime * result  
  54.                 + ((taskDesc == null) ? 0 : taskDesc.hashCode());  
  55.         result = prime * result  
  56.                 + ((taskName == null) ? 0 : taskName.hashCode());  
  57.         result = prime * result + (int) (totalCount ^ (totalCount >>> 32));  
  58.         return result;  
  59.     }  
  60.   
  61.     public String getPkBtTaskId() {  
  62.         return pkBtTaskId;  
  63.     }  
  64.   
  65.     public void setPkBtTaskId(String pkBtTaskId) {  
  66.         this.pkBtTaskId = pkBtTaskId;  
  67.     }  
  68.   
  69.     public String getTaskName() {  
  70.         return taskName;  
  71.     }  
  72.   
  73.     public void setTaskName(String taskName) {  
  74.         this.taskName = taskName;  
  75.     }  
  76.   
  77.     public String getActionType() {  
  78.         return actionType;  
  79.     }  
  80.   
  81.     public void setActionType(String actionType) {  
  82.         this.actionType = actionType;  
  83.     }  
  84.   
  85.     public String getTaskDesc() {  
  86.         return taskDesc;  
  87.     }  
  88.   
  89.     public void setTaskDesc(String taskDesc) {  
  90.         this.taskDesc = taskDesc;  
  91.     }  
  92.   
  93.     public String getStatus() {  
  94.         return status;  
  95.     }  
  96.   
  97.     public void setStatus(String status) {  
  98.         this.status = status;  
  99.     }  
  100.   
  101.     public String getCommitedBy() {  
  102.         return commitedBy;  
  103.     }  
  104.   
  105.     public void setCommitedBy(String commitedBy) {  
  106.         this.commitedBy = commitedBy;  
  107.     }  
  108.   
  109.     public Date getCommitedTime() {  
  110.         return commitedTime;  
  111.     }  
  112.   
  113.     public void setCommitedTime(Date commitedTime) {  
  114.         this.commitedTime = commitedTime;  
  115.     }  
  116.   
  117.     public String getResultLog() {  
  118.         return resultLog;  
  119.     }  
  120.   
  121.     public void setResultLog(String resultLog) {  
  122.         this.resultLog = resultLog;  
  123.     }  
  124.   
  125.     public String getBatchId() {  
  126.         return batchId;  
  127.     }  
  128.   
  129.     public void setBatchId(String batchId) {  
  130.         this.batchId = batchId;  
  131.     }  
  132.   
  133.     public boolean isHeadSkip() {  
  134.         return headSkip;  
  135.     }  
  136.   
  137.     public void setHeadSkip(boolean headSkip) {  
  138.         this.headSkip = headSkip;  
  139.     }  
  140.   
  141.     public String getErrorLogPath() {  
  142.         return errorLogPath;  
  143.     }  
  144.   
  145.     public void setErrorLogPath(String errorLogPath) {  
  146.         this.errorLogPath = errorLogPath;  
  147.     }  
  148.   
  149.     public String getLogRootPath() {  
  150.         return logRootPath;  
  151.     }  
  152.   
  153.     public void setLogRootPath(String logRootPath) {  
  154.         this.logRootPath = logRootPath;  
  155.     }  
  156.   
  157.     public boolean isErrorFlag() {  
  158.         return errorFlag;  
  159.     }  
  160.   
  161.     public void setErrorFlag(boolean errorFlag) {  
  162.         this.errorFlag = errorFlag;  
  163.     }  
  164.   
  165.     public String getCampId() {  
  166.         return campId;  
  167.     }  
  168.   
  169.     public void setCampId(String campId) {  
  170.         this.campId = campId;  
  171.     }  
  172.   
  173.     public String[] getData() {  
  174.         return data;  
  175.     }  
  176.   
  177.     public void setData(String[] data) {  
  178.         this.data = data;  
  179.     }  
  180.   
  181.     public long getTotalCount() {  
  182.         return totalCount;  
  183.     }  
  184.   
  185.     public void setTotalCount(long totalCount) {  
  186.         this.totalCount = totalCount;  
  187.     }  
  188.   
  189.     @Override  
  190.     public boolean equals(Object obj) {  
  191.         if (this == obj) {  
  192.             return true;  
  193.         }  
  194.         if (obj == null) {  
  195.             return false;  
  196.         }  
  197.         if (!(obj instanceof BatchDTO)) {  
  198.             return false;  
  199.         }  
  200.         BatchDTO other = (BatchDTO) obj;  
  201.         if (actionType == null) {  
  202.             if (other.actionType != null) {  
  203.                 return false;  
  204.             }  
  205.         } else if (!actionType.equals(other.actionType)) {  
  206.             return false;  
  207.         }  
  208.         if (batchId == null) {  
  209.             if (other.batchId != null) {  
  210.                 return false;  
  211.             }  
  212.         } else if (!batchId.equals(other.batchId)) {  
  213.             return false;  
  214.         }  
  215.         if (campId == null) {  
  216.             if (other.campId != null) {  
  217.                 return false;  
  218.             }  
  219.         } else if (!campId.equals(other.campId)) {  
  220.             return false;  
  221.         }  
  222.         if (commitedBy == null) {  
  223.             if (other.commitedBy != null) {  
  224.                 return false;  
  225.             }  
  226.         } else if (!commitedBy.equals(other.commitedBy)) {  
  227.             return false;  
  228.         }  
  229.         if (commitedTime == null) {  
  230.             if (other.commitedTime != null) {  
  231.                 return false;  
  232.             }  
  233.         } else if (!commitedTime.equals(other.commitedTime)) {  
  234.             return false;  
  235.         }  
  236.         if (!Arrays.equals(data, other.data)) {  
  237.             return false;  
  238.         }  
  239.         if (errorFlag != other.errorFlag) {  
  240.             return false;  
  241.         }  
  242.         if (errorLogPath == null) {  
  243.             if (other.errorLogPath != null) {  
  244.                 return false;  
  245.             }  
  246.         } else if (!errorLogPath.equals(other.errorLogPath)) {  
  247.             return false;  
  248.         }  
  249.         if (headSkip != other.headSkip) {  
  250.             return false;  
  251.         }  
  252.         if (logRootPath == null) {  
  253.             if (other.logRootPath != null) {  
  254.                 return false;  
  255.             }  
  256.         } else if (!logRootPath.equals(other.logRootPath)) {  
  257.             return false;  
  258.         }  
  259.         if (pkBtTaskId == null) {  
  260.             if (other.pkBtTaskId != null) {  
  261.                 return false;  
  262.             }  
  263.         } else if (!pkBtTaskId.equals(other.pkBtTaskId)) {  
  264.             return false;  
  265.         }  
  266.         if (resultLog == null) {  
  267.             if (other.resultLog != null) {  
  268.                 return false;  
  269.             }  
  270.         } else if (!resultLog.equals(other.resultLog)) {  
  271.             return false;  
  272.         }  
  273.         if (status == null) {  
  274.             if (other.status != null) {  
  275.                 return false;  
  276.             }  
  277.         } else if (!status.equals(other.status)) {  
  278.             return false;  
  279.         }  
  280.         if (taskDesc == null) {  
  281.             if (other.taskDesc != null) {  
  282.                 return false;  
  283.             }  
  284.         } else if (!taskDesc.equals(other.taskDesc)) {  
  285.             return false;  
  286.         }  
  287.         if (taskName == null) {  
  288.             if (other.taskName != null) {  
  289.                 return false;  
  290.             }  
  291.         } else if (!taskName.equals(other.taskName)) {  
  292.             return false;  
  293.         }  
  294.         if (totalCount != other.totalCount) {  
  295.             return false;  
  296.         }  
  297.         return true;  
  298.     }  
  299.   
  300. }  

BatchTask.java

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package batchpoc;  
  2.   
  3. import java.util.concurrent.BlockingQueue;  
  4.   
  5. import org.slf4j.Logger;  
  6. import org.slf4j.LoggerFactory;  
  7.   
  8. public abstract class BatchTask{  
  9.     protected final Logger logger = LoggerFactory.getLogger(this.getClass());  
  10.     public final static String TXT_IMP_EXP = "101";  
  11.     public final static String EXCEL_IMP_EXP = "102";  
  12.     public final static String TASK_RUNNING = "2";  
  13.     public final static String TASK_FINISHED = "4";  
  14.     public final static String TASK_FAILED = "5";  
  15.     protected BatchDTO taskContext = null;  
  16.   
  17.     public BatchTask(BatchDTO taskContext) {  
  18.         this.taskContext = taskContext;  
  19.     }  
  20.   
  21.     public abstract void doBatch() throws Exception;  
  22. }  

EnumerationEngineeFactory.java,用于构建处理“读”多种格式文件的FileParser

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package batchpoc;  
  2.   
  3. import java.util.Map;  
  4. import java.util.concurrent.BlockingQueue;  
  5.   
  6. import util.Constants;  
  7.   
  8. public class EnumerationEngineeFactory {  
  9.   
  10.     public static EnumerationEnginee getInstance(BlockingQueue<Map> queue,  
  11.             String type, String fileName, String colNames, boolean skipHeader,  
  12.             BatchDTO taskContext) {  
  13.         EnumerationEnginee task = null;  
  14.         if (type.equals(Constants.ENUMERATION_TXT_TASK)) {  
  15.             return new TxtEnumerationTask(queue, fileName, colNames,  
  16.                     skipHeader, taskContext);  
  17.         } else if (type.equals(Constants.ENUMERATION_EXCEL_TASK)) {  
  18.             return new XLSEnumerationTask(queue, fileName, colNames,  
  19.                     skipHeader, taskContext);  
  20.         }  
  21.         return task;  
  22.     }  
  23. }  

EnumerationEnginee.java

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package batchpoc;  
  2.   
  3. import java.io.File;  
  4. import java.util.HashMap;  
  5. import java.util.Map;  
  6. import java.util.concurrent.BlockingQueue;  
  7. import java.util.concurrent.CountDownLatch;  
  8.   
  9. import org.slf4j.Logger;  
  10. import org.slf4j.LoggerFactory;  
  11.   
  12. public abstract class EnumerationEnginee implements Runnable {  
  13.     protected String fileName = "";  
  14.     protected String colNames = "";  
  15.     protected final Logger logger = LoggerFactory.getLogger(this.getClass());  
  16.     protected boolean skipHeader = true;  
  17.     protected BatchDTO taskContext = null;  
  18.     protected static Map DUMMY = new HashMap();  
  19.     protected BlockingQueue<Map> queue = null;  
  20.   
  21.     public EnumerationEnginee(BlockingQueue<Map> queue, String fileName,  
  22.             String colNames, boolean skipHeader, BatchDTO taskContext) {  
  23.         this.fileName = fileName;  
  24.         this.colNames = colNames;  
  25.         this.skipHeader = skipHeader;  
  26.         this.taskContext = taskContext;  
  27.         this.queue = queue;  
  28.     }  
  29.   
  30.     public abstract void enumerate(String fileName, String strKeys)  
  31.             throws Exception;  
  32.   
  33.     public abstract void run();  
  34.   
  35. }  

ImportTask.java

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package batchpoc;  
  2.   
  3. import java.util.Iterator;  
  4. import java.util.Map;  
  5. import java.util.concurrent.BlockingQueue;  
  6. import java.util.concurrent.CountDownLatch;  
  7.   
  8. import org.slf4j.Logger;  
  9. import org.slf4j.LoggerFactory;  
  10.   
  11. public class ImportTask implements Runnable {  
  12.     private final Logger logger = LoggerFactory.getLogger(getClass());  
  13.     private BatchDTO taskContext = null;  
  14.     private CountDownLatch threadSignal = null;  
  15.     BlockingQueue<Map> queue = null;  
  16.   
  17.     public ImportTask(BlockingQueue<Map> queue, BatchDTO taskContext,  
  18.             CountDownLatch threadSignal) {  
  19.         this.taskContext = taskContext;  
  20.         this.threadSignal = threadSignal;  
  21.         this.queue = queue;  
  22.     }  
  23.   
  24.     public void run() {  
  25.         boolean done = false;  
  26.         try {  
  27.             synchronized (this) {  
  28.                 while (!done) {  
  29.                     Map data = (Map) queue.take();  
  30.                     if (data == EnumerationEnginee.DUMMY) {  
  31.                         //no data  
  32.                         queue.put(data);  
  33.                         done = true;  
  34.                     } else {  
  35.                         // if (data != null) {  
  36.                         for (Iterator it = data.keySet().iterator(); it  
  37.                                 .hasNext();) {  
  38.                             String key = String.valueOf(it.next());  
  39.                             System.out.print("import:>>>[" + key + "]  :  ["  
  40.                                     + data.get(key) + "]");  
  41.                         }  
  42.                         System.out.println("\n");                         
  43.                     }  
  44.                 }  
  45.             }  
  46.         } catch (Exception e) {  
  47.             logger.error("import file into db error:" + e.getMessage(), e);  
  48.             try {  
  49.                 Thread.interrupted();  
  50.             } catch (Exception ie) {  
  51.             }  
  52.             try {  
  53.                 queue.put(EnumerationEnginee.DUMMY);  
  54.                 done = true;  
  55.             } catch (Exception ex) {  
  56.   
  57.             }  
  58.         } finally {  
  59.             threadSignal.countDown();  
  60.         }  
  61.   
  62.     }  
  63. }  

MapUtil.java-用于Map中根据key值排序用

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package batchpoc;  
  2.   
  3. /* 
  4.  * Author: Mk 
  5.  * Created By: 2012-08-23 
  6.  */  
  7. import java.util.Collections;  
  8. import java.util.Comparator;  
  9. import java.util.LinkedHashMap;  
  10. import java.util.LinkedList;  
  11. import java.util.List;  
  12. import java.util.Map;  
  13.   
  14. public class MapUtil {  
  15.     public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(  
  16.             Map<K, V> map) {  
  17.         List<Map.Entry<K, V>> list = new LinkedList<Map.Entry<K, V>>(  
  18.                 map.entrySet());  
  19.         Collections.sort(list, new Comparator<Map.Entry<K, V>>() {  
  20.             public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {  
  21.                 return (String.valueOf(o1.getKey())).compareTo(String  
  22.                         .valueOf(o2.getKey()));  
  23.             }  
  24.         });  
  25.   
  26.         Map<K, V> result = new LinkedHashMap<K, V>();  
  27.         for (Map.Entry<K, V> entry : list) {  
  28.             result.put(entry.getKey(), entry.getValue());  
  29.         }  
  30.         return result;  
  31.     }  
  32. }  

TxtEnumerationTask.java-这个就是专门用于读txt、csv等文本文件的FileParser,它在EnumerationEngineeFactory被调用

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package batchpoc;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.File;  
  5. import java.io.FileInputStream;  
  6. import java.io.InputStreamReader;  
  7. import java.util.Collections;  
  8. import java.util.Comparator;  
  9. import java.util.HashMap;  
  10. import java.util.Map;  
  11. import java.util.concurrent.BlockingQueue;  
  12.   
  13. import org.slf4j.Logger;  
  14. import org.slf4j.LoggerFactory;  
  15.   
  16. public class TxtEnumerationTask extends EnumerationEnginee {  
  17.     private final Logger logger = LoggerFactory.getLogger(this.getClass());  
  18.   
  19.     public TxtEnumerationTask(BlockingQueue<Map> queue, String txtFileName,  
  20.             String colNames, boolean skipHeader, BatchDTO taskContext) {  
  21.         super(queue, txtFileName, colNames, taskContext.isHeadSkip(),  
  22.                 taskContext);  
  23.   
  24.     }  
  25.   
  26.     @Override  
  27.     public void run() {  
  28.         try {  
  29.             enumerate(super.fileName, super.colNames);  
  30.         } catch (Exception e) {  
  31.             logger.error("read txtFileName error, parse excel quit because :"  
  32.                     + e.getMessage(), e);  
  33.             try {  
  34.                 Thread.interrupted();  
  35.             } catch (Exception ee) {  
  36.             }  
  37.         } finally {  
  38.             try {  
  39.                 queue.put(DUMMY);  
  40.             } catch (Exception ex) {  
  41.             }  
  42.         }  
  43.   
  44.     }  
  45.   
  46.     public void enumerate(String txtFileName, String strKeys) throws Exception {  
  47.         FileInputStream is = null;  
  48.         StringBuilder sb = new StringBuilder();  
  49.         String a_line = "";  
  50.         String[] columnNames = null;  
  51.         String[] cellValues = null;  
  52.         Map dataRow = new HashMap();  
  53.         int i = 0;  
  54.         try {  
  55.             File f = new File(txtFileName);  
  56.             if (f.exists()) {  
  57.                 is = new FileInputStream(new File(txtFileName));  
  58.                 BufferedReader br = new BufferedReader(new InputStreamReader(  
  59.                         is, "UTF-8"));  
  60.                 if (skipHeader) {  
  61.                     br.readLine();  
  62.                 }  
  63.   
  64.                 while ((a_line = br.readLine()) != null) {  
  65.                     if (a_line.trim().length() > 0) {  
  66.                         String[] data = a_line.split(",");  
  67.                         for (int index = 0; index < data.length; index++) {  
  68.                             dataRow.put(String.valueOf(index), data[index]);  
  69.                         }  
  70.                         dataRow = MapUtil.sortByValue(dataRow);  
  71.                         queue.put(dataRow);  
  72.                         dataRow = new HashMap();  
  73.                         i++;  
  74.                     }  
  75.                 }  
  76.             }  
  77.         } catch (Exception e) {  
  78.             throw new Exception("import was interrupted, error happened in "  
  79.                     + i + "  row", e);  
  80.         } finally {  
  81.             try {  
  82.                 if (is != null) {  
  83.                     is.close();  
  84.                     is = null;  
  85.                 }  
  86.             } catch (Exception e) {  
  87.             }  
  88.         }  
  89.     }  
  90. }  


XLSEnumerationTask.java-这个就是专门用于读excel文件的FileParser,它在EnumerationEngineeFactory被调用并且它支持读超过几十万行的XLS文件

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package batchpoc;  
  2.   
  3. import java.io.File;  
  4. import java.util.HashMap;  
  5. import java.util.Map;  
  6. import java.util.concurrent.BlockingQueue;  
  7.   
  8. import org.apache.poi.openxml4j.opc.OPCPackage;  
  9. import org.apache.poi.openxml4j.opc.PackageAccess;  
  10.   
  11. public class XLSEnumerationTask extends EnumerationEnginee {  
  12.   
  13.     public XLSEnumerationTask(BlockingQueue<Map> queue, String txtFileName,  
  14.             String colNames, boolean skipHeader, BatchDTO taskContext) {  
  15.         super(queue, txtFileName, colNames, taskContext.isHeadSkip(),  
  16.                 taskContext);  
  17.     }  
  18.   
  19.     @Override  
  20.     public void enumerate(String fileName, String strKeys) throws Exception {  
  21.         File xlsxFile = new File(fileName);  
  22.         if (xlsxFile.exists()) {  
  23.             // The package open is instantaneous, as it should be.  
  24.             OPCPackage p = OPCPackage.open(xlsxFile.getPath(),  
  25.                     PackageAccess.READ);  
  26.             Map dataMap = new HashMap();  
  27.             XLSXParser xlsxParser = new XLSXParser(p, queue, true);  
  28.             xlsxParser.process();  
  29.         }  
  30.     }  
  31.   
  32.     @Override  
  33.     public void run() {  
  34.         try {  
  35.             enumerate(super.fileName, super.colNames);  
  36.         } catch (Exception e) {  
  37.             logger.error("read excel file error, parse excel quit because :"  
  38.                     + e.getMessage(), e);  
  39.             try {  
  40.                 Thread.interrupted();  
  41.             } catch (Exception ee) {  
  42.             }  
  43.         } finally {  
  44.             try {  
  45.                 // queue.put(DUMMY);  
  46.                 queue.put(DUMMY);  
  47.             } catch (Exception ex) {  
  48.             }  
  49.         }  
  50.   
  51.     }  
  52.   
  53. }  

XLSXParser.java-这个大了,就是用来处理大数据量的XLS文件的

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package batchpoc;  
  2.   
  3. import java.io.File;  
  4. import java.io.IOException;  
  5. import java.io.InputStream;  
  6. import java.util.HashMap;  
  7. import java.util.Iterator;  
  8. import java.util.Map;  
  9. import java.util.concurrent.BlockingQueue;  
  10.   
  11. import javax.xml.parsers.ParserConfigurationException;  
  12. import javax.xml.parsers.SAXParser;  
  13. import javax.xml.parsers.SAXParserFactory;  
  14.   
  15. import org.apache.poi.openxml4j.exceptions.OpenXML4JException;  
  16. import org.apache.poi.openxml4j.opc.OPCPackage;  
  17. import org.apache.poi.openxml4j.opc.PackageAccess;  
  18. import org.apache.poi.ss.usermodel.BuiltinFormats;  
  19. import org.apache.poi.ss.usermodel.DataFormatter;  
  20. import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable;  
  21. import org.apache.poi.xssf.eventusermodel.XSSFReader;  
  22. import org.apache.poi.xssf.model.StylesTable;  
  23. import org.apache.poi.xssf.usermodel.XSSFCellStyle;  
  24. import org.apache.poi.xssf.usermodel.XSSFRichTextString;  
  25. import org.slf4j.Logger;  
  26. import org.slf4j.LoggerFactory;  
  27. import org.xml.sax.Attributes;  
  28. import org.xml.sax.ContentHandler;  
  29. import org.xml.sax.InputSource;  
  30. import org.xml.sax.SAXException;  
  31. import org.xml.sax.XMLReader;  
  32. import org.xml.sax.helpers.DefaultHandler;  
  33.   
  34. /** 
  35.  
  36.  */  
  37. public class XLSXParser {  
  38.   
  39.     private final Logger logger = LoggerFactory.getLogger(getClass());  
  40.   
  41.     /** 
  42.      * The type of the data value is indicated by an attribute on the cell. The 
  43.      * value is usually in a "v" element within the cell. 
  44.      */  
  45.     enum xssfDataType {  
  46.         BOOL, ERROR, FORMULA, INLINESTR, SSTINDEX, NUMBER,  
  47.     }  
  48.   
  49.     int countrows = 0;  
  50.   
  51.     /** 
  52.      * Derived from http://poi.apache.org/spreadsheet/how-to.html#xssf_sax_api 
  53.      * <p/> 
  54.      * Also see Standard ECMA-376, 1st edition, part 4, pages 1928ff, at 
  55.      * http://www.ecma-international.org/publications/standards/Ecma-376.htm 
  56.      * <p/> 
  57.      * A web-friendly version is http://openiso.org/Ecma/376/Part4 
  58.      */  
  59.     class MyXSSFSheetHandler extends DefaultHandler {  
  60.   
  61.         /** 
  62.          * Table with styles 
  63.          */  
  64.         private StylesTable stylesTable;  
  65.         private Map<String, String> dataMap = new HashMap<String, String>();  
  66.         /** 
  67.          * Table with unique strings 
  68.          */  
  69.         private ReadOnlySharedStringsTable sharedStringsTable;  
  70.   
  71.         /** 
  72.          * Destination for data 
  73.          */  
  74.         // private final PrintStream output;  
  75.   
  76.         /** 
  77.          * Number of columns to read starting with leftmost 
  78.          */  
  79.         // private final int minColumnCount;  
  80.   
  81.         // Set when V start element is seen  
  82.         private boolean vIsOpen;  
  83.   
  84.         // Set when cell start element is seen;  
  85.         // used when cell close element is seen.  
  86.         private xssfDataType nextDataType;  
  87.   
  88.         // Used to format numeric cell values.  
  89.         private short formatIndex;  
  90.         private String formatString;  
  91.         private final DataFormatter formatter;  
  92.   
  93.         private int thisRow = 0;  
  94.         private int thisColumn = -1;  
  95.         // The last column printed to the output stream  
  96.         private int lastColumnNumber = -1;  
  97.   
  98.         // Gathers characters as they are seen.  
  99.         private StringBuffer value;  
  100.   
  101.         /** 
  102.          * Accepts objects needed while parsing. 
  103.          *  
  104.          * @param styles 
  105.          *            Table of styles 
  106.          * @param strings 
  107.          *            Table of shared strings 
  108.          * @param cols 
  109.          *            Minimum number of columns to show 
  110.          * @param target 
  111.          *            Sink for output 
  112.          */  
  113.   
  114.         public MyXSSFSheetHandler(StylesTable styles,  
  115.                 ReadOnlySharedStringsTable strings, Map<String, String> dataMap) {  
  116.             this.stylesTable = styles;  
  117.             this.sharedStringsTable = strings;  
  118.             // this.minColumnCount = cols;  
  119.             this.value = new StringBuffer();  
  120.             this.nextDataType = xssfDataType.NUMBER;  
  121.             this.formatter = new DataFormatter();  
  122.             this.dataMap = dataMap;  
  123.         }  
  124.   
  125.         /* 
  126.          * (non-Javadoc) 
  127.          *  
  128.          * @see 
  129.          * org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, 
  130.          * java.lang.String, java.lang.String, org.xml.sax.Attributes) 
  131.          */  
  132.         public void startElement(String uri, String localName, String name,  
  133.                 Attributes attributes) throws SAXException {  
  134.   
  135.             if ("inlineStr".equals(name) || "v".equals(name)) {  
  136.                 vIsOpen = true;  
  137.                 // Clear contents cache  
  138.                 value.setLength(0);  
  139.             }  
  140.             // c => cell  
  141.             else if ("c".equals(name)) {  
  142.                 // Get the cell reference  
  143.                 String r = attributes.getValue("r");  
  144.                 int firstDigit = -1;  
  145.                 for (int c = 0; c < r.length(); ++c) {  
  146.                     if (Character.isDigit(r.charAt(c))) {  
  147.                         firstDigit = c;  
  148.                         break;  
  149.                     }  
  150.                 }  
  151.                 thisColumn = nameToColumn(r.substring(0, firstDigit));  
  152.   
  153.                 // Set up defaults.  
  154.                 this.nextDataType = xssfDataType.NUMBER;  
  155.                 this.formatIndex = -1;  
  156.                 this.formatString = null;  
  157.                 String cellType = attributes.getValue("t");  
  158.                 String cellStyleStr = attributes.getValue("s");  
  159.                 if ("b".equals(cellType))  
  160.                     nextDataType = xssfDataType.BOOL;  
  161.                 else if ("e".equals(cellType))  
  162.                     nextDataType = xssfDataType.ERROR;  
  163.                 else if ("inlineStr".equals(cellType))  
  164.                     nextDataType = xssfDataType.INLINESTR;  
  165.                 else if ("s".equals(cellType))  
  166.                     nextDataType = xssfDataType.SSTINDEX;  
  167.                 else if ("str".equals(cellType))  
  168.                     nextDataType = xssfDataType.FORMULA;  
  169.                 else if (cellStyleStr != null) {  
  170.                     // It's a number, but almost certainly one  
  171.                     // with a special style or format  
  172.                     int styleIndex = Integer.parseInt(cellStyleStr);  
  173.                     XSSFCellStyle style = stylesTable.getStyleAt(styleIndex);  
  174.                     this.formatIndex = style.getDataFormat();  
  175.                     this.formatString = style.getDataFormatString();  
  176.                     if (this.formatString == null)  
  177.                         this.formatString = BuiltinFormats  
  178.                                 .getBuiltinFormat(this.formatIndex);  
  179.                 }  
  180.             }  
  181.   
  182.         }  
  183.   
  184.         /** 
  185.          * 取值 
  186.          *  
  187.          * @param str 
  188.          * @return 
  189.          */  
  190.         public String checkNumber(String str) {  
  191.             str = str.trim();  
  192.             String str2 = "";  
  193.             if (str != null && !"".equals(str)) {  
  194.                 for (int i = 0; i < str.length(); i++) {  
  195.                     if (str.charAt(i) >= 48 && str.charAt(i) <= 57) {  
  196.                         str2 += str.charAt(i);  
  197.                     }  
  198.                 }  
  199.             }  
  200.             return str2.trim();  
  201.         }  
  202.   
  203.         /* 
  204.          * (non-Javadoc) 
  205.          *  
  206.          * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, 
  207.          * java.lang.String, java.lang.String) 
  208.          */  
  209.   
  210.         public void endElement(String uri, String localName, String name)  
  211.                 throws SAXException {  
  212.             String thisStr = null;  
  213.             // System.out.println("endElement----->" + name);  
  214.             // v => contents of a cell  
  215.             if ("v".equals(name)) {  
  216.                 // Process the value contents as required.  
  217.                 // Do now, as characters() may be called more than once  
  218.                 switch (nextDataType) {  
  219.   
  220.                 case BOOL:  
  221.                     char first = value.charAt(0);  
  222.                     thisStr = first == '0' ? "FALSE" : "TRUE";  
  223.                     break;  
  224.   
  225.                 case ERROR:  
  226.                     thisStr = "\"ERROR:" + value.toString() + '"';  
  227.                     break;  
  228.   
  229.                 case FORMULA:  
  230.                     // A formula could result in a string value,  
  231.                     // so always add double-quote characters.  
  232.                     thisStr = '"' + value.toString() + '"';  
  233.                     break;  
  234.   
  235.                 case INLINESTR:  
  236.                     // TODO: have seen an example of this, so it's untested.  
  237.                     XSSFRichTextString rtsi = new XSSFRichTextString(  
  238.                             value.toString());  
  239.                     if (rtsi != null) {  
  240.                         thisStr = rtsi.toString().trim();  
  241.                         thisStr = thisStr.substring(1, thisStr.length() - 1);  
  242.                     }  
  243.                     break;  
  244.   
  245.                 case SSTINDEX:  
  246.                     String sstIndex = value.toString();  
  247.                     try {  
  248.                         int idx = Integer.parseInt(sstIndex);  
  249.                         XSSFRichTextString rtss = new XSSFRichTextString(  
  250.                                 sharedStringsTable.getEntryAt(idx));  
  251.                         if (rtss != null) {  
  252.                             /* 
  253.                              * thisStr = rtss.toString().trim() 
  254.                              * .replaceAll("\\s*", ""); 
  255.                              */  
  256.                             thisStr = checkNumber(rtss.toString().trim());  
  257.                             /* 
  258.                              * thisStr = thisStr .substring(1, thisStr.length() 
  259.                              * - 1); 
  260.                              */  
  261.                         }  
  262.                     } catch (NumberFormatException ex) {  
  263.                         logger.error("Failed to parse SST index '" + sstIndex  
  264.                                 + "': " + ex.toString(), ex);  
  265.                     }  
  266.                     break;  
  267.   
  268.                 case NUMBER:  
  269.                     String n = value.toString();  
  270.                     if (this.formatString != null)  
  271.                         thisStr = formatter.formatRawCellContents(  
  272.                                 Double.parseDouble(n), this.formatIndex,  
  273.                                 this.formatString);  
  274.                     else  
  275.                         thisStr = n;  
  276.                     break;  
  277.   
  278.                 default:  
  279.                     thisStr = "(TODO: Unexpected type: " + nextDataType + ")";  
  280.                     break;  
  281.                 }  
  282.   
  283.                 // Output after we've seen the string contents  
  284.                 // Emit commas for any fields that were missing on this row  
  285.                 if (lastColumnNumber == -1) {  
  286.                     lastColumnNumber = 0;  
  287.                 }  
  288.                 // for (int i = lastColumnNumber; i < thisColumn; ++i) {  
  289.                 // System.out.print("   col: " + i + "  ");  
  290.                 // }  
  291.                 // Might be the empty string.  
  292.                 // output.print(thisStr);  
  293.                 // System.out.println(thisStr);  
  294.                 // System.out.println("thisRow...." + thisRow);  
  295.                 if (thisRow > 0 && thisStr != null  
  296.                         && thisStr.trim().length() > 0) {  
  297.                     // logger.info("dataMap.put()");  
  298.                     dataMap.put(String.valueOf(thisColumn), thisStr);  
  299.   
  300.                 }  
  301.                 // Update column  
  302.                 if (thisColumn > -1)  
  303.                     lastColumnNumber = thisColumn;  
  304.   
  305.             } else if ("row".equals(name)) {  
  306.                 try {  
  307.                     if (dataMap.keySet().size() > 0) {  
  308.                         dataMap = MapUtil.sortByValue(dataMap);  
  309.                         if (toQueue) {  
  310.                             queue.put(dataMap);  
  311.                         }  
  312.                     }  
  313.                 } catch (Exception e) {  
  314.                     logger.error(  
  315.                             "put data into queue error: " + e.getMessage(), e);  
  316.                 }  
  317.                 thisRow++;  
  318.                 dataMap = new HashMap<String, String>();  
  319.                 lastColumnNumber = -1;  
  320.   
  321.             }  
  322.   
  323.         }  
  324.   
  325.         /** 
  326.          * Captures characters only if a suitable element is open. Originally 
  327.          * was just "v"; extended for inlineStr also. 
  328.          */  
  329.         public void characters(char[] ch, int start, int length)  
  330.                 throws SAXException {  
  331.             if (vIsOpen)  
  332.                 value.append(ch, start, length);  
  333.         }  
  334.   
  335.         /** 
  336.          * Converts an Excel column name like "C" to a zero-based index. 
  337.          *  
  338.          * @param name 
  339.          * @return Index corresponding to the specified name 
  340.          */  
  341.         private int nameToColumn(String name) {  
  342.             int column = -1;  
  343.             for (int i = 0; i < name.length(); ++i) {  
  344.                 int c = name.charAt(i);  
  345.                 column = (column + 1) * 26 + c - 'A';  
  346.             }  
  347.             return column;  
  348.         }  
  349.   
  350.     }  
  351.   
  352.     // /  
  353.   
  354.     private OPCPackage xlsxPackage;  
  355.     private BlockingQueue<Map> queue = null;  
  356.     private boolean toQueue = false;  
  357.   
  358.     // private int minColumns;  
  359.   
  360.     // private PrintStream output;  
  361.   
  362.     /** 
  363.      * Creates a new XLSX -> XML converter 
  364.      *  
  365.      * @param pkg 
  366.      *            The XLSX package to process 
  367.      * @param output 
  368.      *            The PrintStream to output the CSV to 
  369.      * @param minColumns 
  370.      *            The minimum number of columns to output, or -1 for no minimum 
  371.      */  
  372.     public XLSXParser(OPCPackage pkg, BlockingQueue<Map> queue, boolean toQueue) {  
  373.         this.xlsxPackage = pkg;  
  374.         this.queue = queue;  
  375.         this.toQueue = toQueue;  
  376.         // this.minColumns = minColumns;  
  377.     }  
  378.   
  379.     /** 
  380.      * Parses and shows the content of one sheet using the specified styles and 
  381.      * shared-strings tables. 
  382.      *  
  383.      * @param styles 
  384.      * @param strings 
  385.      * @param sheetInputStream 
  386.      */  
  387.     public void processSheet(StylesTable styles,  
  388.             ReadOnlySharedStringsTable strings, InputStream sheetInputStream)  
  389.             throws IOException, ParserConfigurationException, SAXException {  
  390.   
  391.         InputSource sheetSource = new InputSource(sheetInputStream);  
  392.         SAXParserFactory saxFactory = SAXParserFactory.newInstance();  
  393.         SAXParser saxParser = saxFactory.newSAXParser();  
  394.         XMLReader sheetParser = saxParser.getXMLReader();  
  395.         Map<String, String> dataMap = new HashMap<String, String>();  
  396.         ContentHandler handler = new MyXSSFSheetHandler(styles, strings,  
  397.                 dataMap);  
  398.         sheetParser.setContentHandler(handler);  
  399.         sheetParser.parse(sheetSource);  
  400.     }  
  401.   
  402.     /** 
  403.      * Initiates the processing of the XLS workbook file to CSV. 
  404.      *  
  405.      * @throws IOException 
  406.      * @throws OpenXML4JException 
  407.      * @throws ParserConfigurationException 
  408.      * @throws SAXException 
  409.      */  
  410.     public void process() throws IOException, OpenXML4JException,  
  411.             ParserConfigurationException, SAXException {  
  412.   
  413.         ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(  
  414.                 this.xlsxPackage);  
  415.         XSSFReader xssfReader = new XSSFReader(this.xlsxPackage);  
  416.   
  417.         StylesTable styles = xssfReader.getStylesTable();  
  418.         XSSFReader.SheetIterator iter = (XSSFReader.SheetIterator) xssfReader  
  419.                 .getSheetsData();  
  420.         int index = 0;  
  421.         while (iter.hasNext()) {  
  422.             InputStream stream = iter.next();  
  423.             String sheetName = iter.getSheetName();  
  424.             // System.out.println(sheetName + " [index=" + index + "]:");  
  425.             processSheet(styles, strings, stream);  
  426.             stream.close();  
  427.             ++index;  
  428.         }  
  429.     }  
  430.   
  431.     public static void main(String[] args) throws Exception {  
  432.         /* 
  433.          * if (args.length < 1) { System.err.println("Use:"); 
  434.          * System.err.println("  XLSX2CSV <xlsx file> [min columns]"); return; } 
  435.          */  
  436.   
  437.         // File xlsxFile = new File(args[0]);  
  438.         File xlsxFile = new File("d:/test.xlsx");  
  439.         if (!xlsxFile.exists()) {  
  440.             System.err  
  441.                     .println("Not found or not a file: " + xlsxFile.getPath());  
  442.             return;  
  443.         }  
  444.   
  445.         int minColumns = -1;  
  446.         // if (args.length >= 2)  
  447.         // minColumns = Integer.parseInt(args[1]);  
  448.   
  449.         minColumns = 2;  
  450.         // The package open is instantaneous, as it should be.  
  451.         OPCPackage p = OPCPackage.open(xlsxFile.getPath(), PackageAccess.READ);  
  452.         XLSXParser xlsxParser = new XLSXParser(p, nullfalse);  
  453.         xlsxParser.process();  
  454.     }  
  455.   
  456. }  

这个用的是 POI3.5以上版本并且需要有下面这几个LIB库辅助支持才能编译和运行通过:
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <!-- poi start -->  
  2.     <dependency>  
  3.         <groupId>org.apache.poi</groupId>  
  4.         <artifactId>poi</artifactId>  
  5.         <version>${poi_version}</version>  
  6.     </dependency>  
  7.     <dependency>  
  8.         <groupId>org.apache.poi</groupId>  
  9.         <artifactId>poi-ooxml-schemas</artifactId>  
  10.         <version>${poi_version}</version>  
  11.     </dependency>  
  12.     <dependency>  
  13.         <groupId>org.apache.poi</groupId>  
  14.         <artifactId>poi-scratchpad</artifactId>  
  15.         <version>${poi_version}</version>  
  16.     </dependency>  
  17.         <dependency>  
  18.     <groupId>org.apache.poi</groupId>  
  19.     <artifactId>poi-ooxml</artifactId>  
  20.     <version>${poi_version}</version>  
  21. </dependency>  
  22. <!-- poi end -->  

我在这边使用的是3.8,回头会给出详细的pom.xml文件
它不是按照传统的load内存的文式去读这个xls文件,而是把xls文件当成一个xml然后以SAX的模式去读取这个excel。

关键处理部位
public void endElement(String uri, String localName, String name)方法中如下语句:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. if (thisRow > 0 && thisStr != null&& thisStr.trim().length() > 0) {  
  2.     // logger.info("dataMap.put()");  
  3.     dataMap.put(String.valueOf(thisColumn), thisStr);  
  4.                       
  5. }  


[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. else if ("row".equals(name)) {  
  2.         try {  
  3.             if (dataMap.keySet().size() > 0) {  
  4.                 dataMap = MapUtil.sortByValue(dataMap);  
  5.                 if (toQueue) {  
  6.                     queue.put(dataMap);  
  7.                 }  
  8.             }  
  9.         } catch (Exception e) {  
  10.             logger.error(  
  11.                     "put data into queue error: " + e.getMessage(), e);  
  12.         }  

其它辅助类

UUID.java

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package batchpoc;  
  2.   
  3. public class UUID {  
  4.     protected static int count = 0;  
  5.   
  6.     public static synchronized String getUUID() {  
  7.         count++;  
  8.         long time = System.currentTimeMillis();  
  9.   
  10.         String timePattern = Long.toHexString(time);  
  11.         int leftBit = 14 - timePattern.length();  
  12.         if (leftBit > 0) {  
  13.             timePattern = "0000000000".substring(0, leftBit) + timePattern;  
  14.         }  
  15.   
  16.         String uuid = timePattern  
  17.                 + Long.toHexString(Double.doubleToLongBits(Math.random()))  
  18.                 + Long.toHexString(Double.doubleToLongBits(Math.random()))  
  19.                 + "000000000000000000";  
  20.   
  21.         uuid = uuid.substring(032).toUpperCase();  
  22.   
  23.         return uuid;  
  24.     }  
  25. }  

GuidCreator.java

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package batchpoc;  
  2.   
  3. import java.net.*;  
  4. import java.util.*;  
  5. import java.security.*;  
  6.   
  7. public class GuidCreator {  
  8.     private String seedingString = "";  
  9.     private String rawGUID = "";  
  10.     private boolean bSecure = false;  
  11.     private static Random myRand;  
  12.     private static SecureRandom mySecureRand;  
  13.   
  14.     private static String s_id;  
  15.   
  16.     public static final int BeforeMD5 = 1;  
  17.     public static final int AfterMD5 = 2;  
  18.     public static final int FormatString = 3;  
  19.     static {  
  20.         mySecureRand = new SecureRandom();  
  21.         long secureInitializer = mySecureRand.nextLong();  
  22.         myRand = new Random(secureInitializer);  
  23.         try {  
  24.             s_id = InetAddress.getLocalHost().toString();  
  25.         } catch (UnknownHostException e) {  
  26.             e.printStackTrace();  
  27.         }  
  28.     }  
  29.   
  30.     public GuidCreator() {  
  31.     }  
  32.   
  33.     /* 
  34.      * Constructor with security option. Setting secure true enables each random 
  35.      * number generated to be cryptographically strong. Secure false defaults to 
  36.      * the standard Random function seeded with a single cryptographically 
  37.      * strong random number. 
  38.      */  
  39.     public GuidCreator(boolean secure) {  
  40.         bSecure = secure;  
  41.     }  
  42.   
  43.     /* 
  44.      * Method to generate the random GUID 
  45.      */  
  46.     private void getRandomGUID(boolean secure) {  
  47.         MessageDigest md5 = null;  
  48.         StringBuffer sbValueBeforeMD5 = new StringBuffer();  
  49.   
  50.         try {  
  51.             md5 = MessageDigest.getInstance("MD5");  
  52.         } catch (NoSuchAlgorithmException e) {  
  53.             System.out.println("Error: " + e);  
  54.         }  
  55.   
  56.         try {  
  57.             long time = System.currentTimeMillis();  
  58.             long rand = 0;  
  59.   
  60.             if (secure) {  
  61.                 rand = mySecureRand.nextLong();  
  62.             } else {  
  63.                 rand = myRand.nextLong();  
  64.             }  
  65.   
  66.             // This StringBuffer can be a long as you need; the MD5  
  67.             // hash will always return 128 bits. You can change  
  68.             // the seed to include anything you want here.  
  69.             // You could even stream a file through the MD5 making  
  70.             // the odds of guessing it at least as great as that  
  71.             // of guessing the contents of the file!  
  72.             sbValueBeforeMD5.append(s_id);  
  73.             sbValueBeforeMD5.append(":");  
  74.             sbValueBeforeMD5.append(Long.toString(time));  
  75.             sbValueBeforeMD5.append(":");  
  76.             sbValueBeforeMD5.append(Long.toString(rand));  
  77.   
  78.             seedingString = sbValueBeforeMD5.toString();  
  79.             md5.update(seedingString.getBytes());  
  80.   
  81.             byte[] array = md5.digest();  
  82.             StringBuffer sb = new StringBuffer();  
  83.             for (int j = 0; j < array.length; ++j) {  
  84.                 int b = array[j] & 0xFF;  
  85.                 if (b < 0x10)  
  86.                     sb.append('0');  
  87.                 sb.append(Integer.toHexString(b));  
  88.             }  
  89.   
  90.             rawGUID = sb.toString();  
  91.   
  92.         } catch (Exception e) {  
  93.             System.out.println("Error:" + e);  
  94.         }  
  95.     }  
  96.   
  97.     public String createNewGuid(int nFormatType, boolean secure) {  
  98.         getRandomGUID(secure);  
  99.         String sGuid = "";  
  100.         if (BeforeMD5 == nFormatType) {  
  101.             sGuid = this.seedingString;  
  102.         } else if (AfterMD5 == nFormatType) {  
  103.             sGuid = this.rawGUID;  
  104.         } else {  
  105.             sGuid = this.toString();  
  106.         }  
  107.         return sGuid;  
  108.     }  
  109.   
  110.     public String createNewGuid(int nFormatType) {  
  111.         return this.createNewGuid(nFormatType, this.bSecure);  
  112.     }  
  113.   
  114.     /* 
  115.      * Convert to the standard format for GUID (Useful for SQL Server 
  116.      * UniqueIdentifiers, etc.) Example: C2FEEEAC-CFCD-11D1-8B05-00600806D9B6 
  117.      */  
  118.     public String toString() {  
  119.         String raw = rawGUID.toUpperCase();  
  120.         StringBuffer sb = new StringBuffer();  
  121.         sb.append(raw.substring(08));  
  122.         sb.append("-");  
  123.         sb.append(raw.substring(812));  
  124.         sb.append("-");  
  125.         sb.append(raw.substring(1216));  
  126.         sb.append("-");  
  127.         sb.append(raw.substring(1620));  
  128.         sb.append("-");  
  129.         sb.append(raw.substring(20));  
  130.   
  131.         return sb.toString();  
  132.     }  
  133.   
  134.     public static void main(String args[]) {  
  135.         GuidCreator myGUID = new GuidCreator();  
  136. //      System.out.println("Seeding String="  
  137. //              + myGUID.createNewGuid(GuidCreator.BeforeMD5));  
  138. //      System.out.println("rawGUID="  
  139. //              + myGUID.createNewGuid(GuidCreator.AfterMD5));  
  140.         System.out.println("RandomGUID="  
  141.                 + myGUID.createNewGuid(GuidCreator.AfterMD5));  
  142.     }  
  143. }  

GuidByRandom.java

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package batchpoc;  
  2.   
  3. import java.text.SimpleDateFormat;  
  4.   
  5. public class GuidByRandom {  
  6.     private static int cnt = 0;  
  7.   
  8.     public static synchronized String getGUID() throws Exception {  
  9.         StringBuffer code = new StringBuffer();  
  10.         try {  
  11.             java.util.Date dt = new java.util.Date(System.currentTimeMillis());  
  12.             SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMddHHmmssSSS");//format system time   
  13.             String randomCode = fmt.format(dt);  
  14.             cnt = (cnt + 1) % 10000// You are free the set %100 to  
  15.             // 1000,100000  
  16.             code.append(randomCode).append(cnt);  
  17.             return code.toString();  
  18.         } catch (Exception e) {  
  19.             throw new Exception("createFileName error:" + e.getMessage(), e);  
  20.         }  
  21.     }  
  22.   
  23.     public static void main(String[] args) throws Exception {  
  24.         System.out.println(getGUID());  
  25.     }  
  26. }  

Constants.java

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package util;  
  2.   
  3. public class Constants {  
  4.   
  5.     public final static String ENUMERATION_EXCEL_TASK = "excel";  
  6.     public final static String ENUMERATION_TXT_TASK = "txt";  
  7. }  

StringUtil.java

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package util;  
  2.   
  3. import java.io.ByteArrayInputStream;  
  4. import java.io.ByteArrayOutputStream;  
  5. import java.io.ObjectInputStream;  
  6. import java.io.ObjectOutputStream;  
  7. import java.util.Calendar;  
  8. import java.util.Date;  
  9. import java.sql.Blob;  
  10. import java.text.*;  
  11. import java.util.regex.Pattern;  
  12.   
  13. import org.slf4j.Logger;  
  14. import org.slf4j.LoggerFactory;  
  15.   
  16. public class StringUtil {  
  17.     protected final static Logger logger = LoggerFactory  
  18.             .getLogger(StringUtil.class);  
  19.   
  20.     public static Object unserializeObj(byte[] bytes) {  
  21.         ByteArrayInputStream bais = null;  
  22.         try {  
  23.             // 反序列化  
  24.             bais = new ByteArrayInputStream(bytes);  
  25.             ObjectInputStream ois = new ObjectInputStream(bais);  
  26.             return ois.readObject();  
  27.         } catch (Exception e) {  
  28.             logger.error("unserializeObj error:" + e.getMessage(), e);  
  29.         }  
  30.         return null;  
  31.     }  
  32.   
  33.     public static byte[] serializeObj(Object obj) {  
  34.         ByteArrayOutputStream bout = null;  
  35.         ObjectOutputStream out = null;  
  36.         byte[] bytes = null;  
  37.         try {  
  38.             bout = new ByteArrayOutputStream();  
  39.             out = new ObjectOutputStream(bout);  
  40.             out.writeObject(obj);  
  41.             out.flush();  
  42.             bytes = bout.toByteArray();  
  43.         } catch (Exception e) {  
  44.             logger.error("serializeObject error:" + e.getMessage(), e);  
  45.         } finally {  
  46.             try {  
  47.                 if (out != null) {  
  48.                     out.close();  
  49.                     out = null;  
  50.                 }  
  51.             } catch (Exception e) {  
  52.             }  
  53.             try {  
  54.                 if (bout != null) {  
  55.                     bout.close();  
  56.                     bout = null;  
  57.                 }  
  58.             } catch (Exception e) {  
  59.             }  
  60.         }  
  61.         return bytes;  
  62.     }  
  63.   
  64.     public static String escpaeCharacters(String s) {  
  65.         String val = "";  
  66.         try {  
  67.             if (s == null || s.length() < 1) {  
  68.                 return s;  
  69.             }  
  70.             StringBuilder sb = new StringBuilder(s.length() + 16);  
  71.             for (int i = 0; i < s.length(); i++) {  
  72.                 char c = s.charAt(i);  
  73.                 switch (c) {  
  74.                 case '\'':  
  75.                     sb.append("′");// ´");  
  76.                     break;  
  77.                 case '′':  
  78.                     sb.append("′");// ´");  
  79.                     break;  
  80.                 case '\"':  
  81.                     sb.append(""");  
  82.                     break;  
  83.                 case '"':  
  84.                     sb.append(""");  
  85.                     break;  
  86.                 case '&':  
  87.                     sb.append("&");  
  88.                     break;  
  89.                 case '#':  
  90.                     sb.append("#");  
  91.                     break;  
  92.                 case '\\':  
  93.                     sb.append('¥');  
  94.                     break;  
  95.   
  96.                 case '>':  
  97.                     sb.append('>');  
  98.                     break;  
  99.                 case '<':  
  100.                     sb.append('<');  
  101.                     break;  
  102.                 default:  
  103.                     sb.append(c);  
  104.                     break;  
  105.                 }  
  106.             }  
  107.             val = sb.toString();  
  108.             return val;  
  109.         } catch (Exception e) {  
  110.             logger.error("sanitized characters error: " + e.getMessage(), e);  
  111.             return s;  
  112.         }  
  113.     }  
  114.   
  115.     public static boolean isNotNullOrEmpty(String str) {  
  116.         return str != null && str.trim().length() > 0;  
  117.     }  
  118.   
  119.     public static boolean isNull(Object... params) {  
  120.         if (params == null) {  
  121.             return true;  
  122.         }  
  123.   
  124.         for (Object obj : params) {  
  125.             if (obj == null) {  
  126.                 return true;  
  127.             }  
  128.         }  
  129.         return false;  
  130.     }  
  131.   
  132.     public static String getString(Object val) {  
  133.         String rtnVal = "";  
  134.         try {  
  135.             rtnVal = (String) val;  
  136.             rtnVal = rtnVal.trim();  
  137.         } catch (Exception e) {  
  138.             rtnVal = "";  
  139.         }  
  140.         return rtnVal;  
  141.     }  
  142.   
  143.     public static String nullToStr(Object val) {  
  144.         return ((val == null) ? "" : String.valueOf(val).trim());  
  145.     }  
  146.   
  147.     public static int getInt(Object val) {  
  148.         int rtnVal = -1;  
  149.         String rtnValStr = "-1";  
  150.         try {  
  151.             rtnValStr = (String) val;  
  152.             rtnValStr = rtnValStr.trim();  
  153.             rtnVal = Integer.parseInt(rtnValStr);  
  154.         } catch (Exception e) {  
  155.             rtnVal = -1;  
  156.         }  
  157.   
  158.         return rtnVal;  
  159.     }  
  160.   
  161.     public static String convertDateToStr(Date dt) {  
  162.         String dateStr = "";  
  163.         DateFormat format = new SimpleDateFormat("yyyy-MM-dd");  
  164.         if (dt != null) {  
  165.             dateStr = format.format(dt);  
  166.         }  
  167.         return dateStr;  
  168.     }  
  169.   
  170.     public static String convertDateToStr(Date dt, String formatter) {  
  171.         String dateStr = "";  
  172.         DateFormat format = new SimpleDateFormat(formatter);  
  173.         if (dt != null) {  
  174.             dateStr = format.format(dt);  
  175.         }  
  176.         return dateStr;  
  177.     }  
  178.   
  179.     public static Date convertStrToDateByFormat(String dateStr) {  
  180.         String inputDateStr = "";  
  181.         SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");  
  182.         Date date = null;  
  183.         try {  
  184.             inputDateStr = dateStr;  
  185.             if (dateStr == null || dateStr.trim().length() < 1) {  
  186.                 inputDateStr = "1900-01-01";  
  187.             }  
  188.             java.util.Date d = sf.parse(inputDateStr.toString().trim());  
  189.             date = new Date(d.getTime());  
  190.         } catch (Exception e) {  
  191.             logger.error(  
  192.                     "convertStrToDateByFormat(" + dateStr + ") error:"  
  193.                             + e.getMessage(), e);  
  194.         }  
  195.         return date;  
  196.     }  
  197.   
  198.     public static Date convertStrToDateByFormat(String dateStr, String formatter) {  
  199.         String inputDateStr = "";  
  200.         SimpleDateFormat sf = new SimpleDateFormat(formatter);  
  201.         Date date = null;  
  202.         try {  
  203.             inputDateStr = dateStr;  
  204.             if (dateStr == null || dateStr.trim().length() < 1) {  
  205.                 inputDateStr = "1900-01-01 01:01:01";  
  206.             }  
  207.             java.util.Date d = sf.parse(inputDateStr.toString().trim());  
  208.             date = new Date(d.getTime());  
  209.         } catch (Exception e) {  
  210.             logger.error(  
  211.                     "convertStrToDateByFormat(" + dateStr + ") error:"  
  212.                             + e.getMessage(), e);  
  213.         }  
  214.         return date;  
  215.     }  
  216.   
  217.     public static Object deepcopy(Object src) throws Exception {  
  218.         ByteArrayOutputStream byteout = null;  
  219.         ObjectOutputStream out = null;  
  220.         ByteArrayInputStream bytein = null;  
  221.         ObjectInputStream in = null;  
  222.         Object dest = null;  
  223.         try {  
  224.             byteout = new ByteArrayOutputStream();  
  225.             out = new ObjectOutputStream(byteout);  
  226.             out.writeObject(src);  
  227.   
  228.             bytein = new ByteArrayInputStream(byteout.toByteArray());  
  229.   
  230.             in = new ObjectInputStream(bytein);  
  231.   
  232.             dest = (Object) in.readObject();  
  233.         } catch (Exception e) {  
  234.             throw new Exception("deep copy object[" + src  
  235.                     + "] error cause by: " + e.getMessage(), e);  
  236.         } finally {  
  237.             try {  
  238.                 if (in != null) {  
  239.                     in.close();  
  240.                     in = null;  
  241.                 }  
  242.             } catch (Exception e) {  
  243.             }  
  244.             try {  
  245.                 if (bytein != null) {  
  246.                     bytein.close();  
  247.                     bytein = null;  
  248.                 }  
  249.             } catch (Exception e) {  
  250.             }  
  251.             try {  
  252.                 if (out != null) {  
  253.                     out.close();  
  254.                     out = null;  
  255.                 }  
  256.             } catch (Exception e) {  
  257.             }  
  258.             try {  
  259.                 if (byteout != null) {  
  260.                     byteout.close();  
  261.                     byteout = null;  
  262.                 }  
  263.             } catch (Exception e) {  
  264.             }  
  265.         }  
  266.         return dest;  
  267.   
  268.     }  
  269.   
  270.     public static Object blobToObject(Blob blob) throws Exception {  
  271.         Object obj = null;  
  272.         ObjectInputStream in = null;  
  273.         try {  
  274.             in = new ObjectInputStream(blob.getBinaryStream());  
  275.             obj = in.readObject();  
  276.             return obj;  
  277.         } catch (Exception e) {  
  278.             throw new Exception(e);  
  279.         } finally {  
  280.             try {  
  281.                 if (in != null) {  
  282.                     in.close();  
  283.                     in = null;  
  284.                 }  
  285.             } catch (Exception e) {  
  286.             }  
  287.         }  
  288.     }  
  289.   
  290.     public static long dateSub(String dateStr) throws ParseException {  
  291.         SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");  
  292.         java.util.Date d = sdf.parse(dateStr);  
  293.         Calendar calendar = Calendar.getInstance();  
  294.         calendar.setTime(new Date());  
  295.         long currentTime = calendar.getTimeInMillis();  
  296.         calendar.setTime(d);  
  297.         long timeEnd = calendar.getTimeInMillis();  
  298.         long theDay = (timeEnd - currentTime) / (1000 * 60 * 60 * 24);  
  299.         return theDay;  
  300.     }  
  301.   
  302.     public static boolean isNumeric(String str) {  
  303.         Pattern pattern = Pattern.compile("[0-9]*");  
  304.         return pattern.matcher(str).matches();  
  305.     }  
  306. }  

工程使用maven,因此给出pom.xml完整内容

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  2.     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  3.     <modelVersion>4.0.0</modelVersion>  
  4.     <groupId>webpoc</groupId>  
  5.     <artifactId>webpoc</artifactId>  
  6.     <version>0.0.1-SNAPSHOT</version>  
  7.     <packaging>war</packaging>  
  8.     <properties>  
  9.         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
  10.         <java.version>1.8</java.version>  
  11.         <jetty.version>9.3.3.v20150827</jetty.version>  
  12.         <slf4j.version>1.7.7</slf4j.version>  
  13.         <spring.version>4.2.1.RELEASE</spring.version>  
  14.         <spring.session.version>1.0.2.RELEASE</spring.session.version>  
  15.         <javax.servlet-api.version>2.5</javax.servlet-api.version>  
  16.         <activemq_version>5.8.0</activemq_version>  
  17.         <poi_version>3.8</poi_version>  
  18.     </properties>  
  19.     <dependencies>  
  20.   
  21.         <!-- poi start -->  
  22.         <dependency>  
  23.             <groupId>org.apache.poi</groupId>  
  24.             <artifactId>poi</artifactId>  
  25.             <version>${poi_version}</version>  
  26.         </dependency>  
  27.         <dependency>  
  28.             <groupId>org.apache.poi</groupId>  
  29.             <artifactId>poi-ooxml-schemas</artifactId>  
  30.             <version>${poi_version}</version>  
  31.         </dependency>  
  32.         <dependency>  
  33.             <groupId>org.apache.poi</groupId>  
  34.             <artifactId>poi-scratchpad</artifactId>  
  35.             <version>${poi_version}</version>  
  36.         </dependency>  
  37.         <dependency>  
  38.             <groupId>org.apache.poi</groupId>  
  39.             <artifactId>poi-ooxml</artifactId>  
  40.             <version>${poi_version}</version>  
  41.         </dependency>  
  42.         <!-- poi end -->  
  43.         <!-- active mq start -->  
  44.         <dependency>  
  45.             <groupId>org.apache.activemq</groupId>  
  46.             <artifactId>activemq-all</artifactId>  
  47.             <version>5.8.0</version>  
  48.         </dependency>  
  49.   
  50.         <dependency>  
  51.             <groupId>org.apache.activemq</groupId>  
  52.             <artifactId>activemq-pool</artifactId>  
  53.             <version>${activemq_version}</version>  
  54.         </dependency>  
  55.   
  56.         <dependency>  
  57.             <groupId>org.apache.xbean</groupId>  
  58.             <artifactId>xbean-spring</artifactId>  
  59.             <version>3.16</version>  
  60.         </dependency>  
  61.         <!-- active mq end -->  
  62.   
  63.         <!-- servlet start -->  
  64.         <dependency>  
  65.             <groupId>javax.servlet</groupId>  
  66.             <artifactId>servlet-api</artifactId>  
  67.             <version>${javax.servlet-api.version}</version>  
  68.             <scope>provided</scope>  
  69.         </dependency>  
  70.         <dependency>  
  71.             <groupId>javax.servlet.jsp</groupId>  
  72.             <artifactId>jsp-api</artifactId>  
  73.             <version>2.1</version>  
  74.             <scope>provided</scope>  
  75.         </dependency>  
  76.         <dependency>  
  77.             <groupId>javax.servlet</groupId>  
  78.             <artifactId>jstl</artifactId>  
  79.             <version>1.2</version>  
  80.         </dependency>  
  81.         <!-- servlet end -->  
  82.   
  83.         <!-- redis start -->  
  84.         <dependency>  
  85.             <groupId>redis.clients</groupId>  
  86.             <artifactId>jedis</artifactId>  
  87.             <version>2.5.2</version>  
  88.         </dependency>  
  89.         <dependency>  
  90.             <groupId>org.redisson</groupId>  
  91.             <artifactId>redisson</artifactId>  
  92.             <version>1.0.2</version>  
  93.         </dependency>  
  94.         <!-- redis end -->  
  95.         <dependency>  
  96.             <groupId>org.slf4j</groupId>  
  97.             <artifactId>jcl-over-slf4j</artifactId>  
  98.             <version>${slf4j.version}</version>  
  99.         </dependency>  
  100.         <dependency>  
  101.             <groupId>org.slf4j</groupId>  
  102.             <artifactId>slf4j-log4j12</artifactId>  
  103.             <version>${slf4j.version}</version>  
  104.         </dependency>  
  105.   
  106.         <!-- spring conf start -->  
  107.         <dependency>  
  108.             <groupId>org.springframework.data</groupId>  
  109.             <artifactId>spring-data-redis</artifactId>  
  110.             <version>1.5.2.RELEASE</version>  
  111.         </dependency>  
  112.         <dependency>  
  113.             <groupId>org.springframework</groupId>  
  114.             <artifactId>spring-webmvc</artifactId>  
  115.             <version>${spring.version}</version>  
  116.             <exclusions>  
  117.                 <exclusion>  
  118.                     <groupId>commons-logging</groupId>  
  119.                     <artifactId>commons-logging</artifactId>  
  120.                 </exclusion>  
  121.             </exclusions>  
  122.         </dependency>  
  123.         <dependency>  
  124.             <groupId>org.springframework</groupId>  
  125.             <artifactId>spring-tx</artifactId>  
  126.             <version>${spring.version}</version>  
  127.         </dependency>  
  128.         <dependency>  
  129.             <groupId>org.springframework</groupId>  
  130.             <artifactId>spring-aop</artifactId>  
  131.             <version>${spring.version}</version>  
  132.         </dependency>  
  133.         <dependency>  
  134.             <groupId>org.springframework</groupId>  
  135.             <artifactId>spring-context-support</artifactId>  
  136.             <version>${spring.version}</version>  
  137.         </dependency>  
  138.         <dependency>  
  139.             <groupId>org.springframework.data</groupId>  
  140.             <artifactId>spring-data-redis</artifactId>  
  141.             <version>1.4.1.RELEASE</version>  
  142.         </dependency>  
  143.   
  144.         <dependency>  
  145.             <groupId>org.springframework</groupId>  
  146.             <artifactId>spring-orm</artifactId>  
  147.             <version>${spring.version}</version>  
  148.         </dependency>  
  149.   
  150.   
  151.         <dependency>  
  152.             <groupId>org.springframework</groupId>  
  153.             <artifactId>spring-jms</artifactId>  
  154.             <version>${spring.version}</version>  
  155.         </dependency>  
  156.   
  157.         <dependency>  
  158.             <groupId>org.springframework.session</groupId>  
  159.             <artifactId>spring-session</artifactId>  
  160.             <version>${spring.session.version}</version>  
  161.         </dependency>  
  162.         <dependency>  
  163.             <groupId>org.springframework</groupId>  
  164.             <artifactId>spring-core</artifactId>  
  165.             <version>${spring.version}</version>  
  166.         </dependency>  
  167.         <!-- spring conf end -->  
  168.     </dependencies>  
  169.     <build>  
  170.         <sourceDirectory>src</sourceDirectory>  
  171.         <plugins>  
  172.             <plugin>  
  173.                 <artifactId>maven-compiler-plugin</artifactId>  
  174.                 <version>3.1</version>  
  175.                 <configuration>  
  176.                     <source>1.7</source>  
  177.                     <target>1.7</target>  
  178.                 </configuration>  
  179.             </plugin>  
  180.             <plugin>  
  181.                 <artifactId>maven-war-plugin</artifactId>  
  182.                 <version>2.4</version>  
  183.                 <configuration>  
  184.                     <warSourceDirectory>WebContent</warSourceDirectory>  
  185.                     <failOnMissingWebXml>false</failOnMissingWebXml>  
  186.                 </configuration>  
  187.             </plugin>  
  188.         </plugins>  
  189.     </build>  
  190. </project>  


给出实际调用代码-即如何使用这套批处理数据框架

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package batchpoc;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.Date;  
  5. import java.util.List;  
  6.   
  7. import util.Constants;  
  8.   
  9. public class TestImpLogfile {  
  10.   
  11.     /** 
  12.      * @param args 
  13.      */  
  14.     public static void main(String[] args) {  
  15.         //final String fileName = "d:/log_small.csv";  
  16.         final String fileName = "d:/test_big.xlsx";  
  17.         try {  
  18.             GuidCreator myGUID = new GuidCreator();  
  19.             BatchDTO taskContext = new BatchDTO();  
  20.             String batchId = myGUID.createNewGuid(GuidCreator.AfterMD5);  
  21.             taskContext.setPkBtTaskId(batchId);  
  22.             taskContext.setTaskName(BatchTask.TXT_IMP_EXP);  
  23.             taskContext.setTaskDesc(fileName);  
  24.             taskContext.setCommitedBy("unittest");  
  25.             taskContext.setStatus(BatchTask.TASK_RUNNING);  
  26.             taskContext.setCommitedTime(new Date());  
  27.             taskContext.setBatchId(batchId);  
  28.             taskContext.setHeadSkip(true);  
  29.             //BatchImportExec task = new BatchImportExec(  
  30.             //      Constants.ENUMERATION_TXT_TASK, fileName, "", taskContext);  
  31.             task.doBatch();  
  32.             // if (data != null && data.size() > 0) {  
  33.             // for (int i = 0; i < data.size(); i++) {  
  34.             // System.out.println("rows: " + i + "=====" + data.get(i));  
  35.             // }  
  36.             // }  
  37.             BatchImportExec task = new BatchImportExec( Constants.ENUMERATION_EXCEL_TASK, fileName, "", taskContext);  
  38.                         task.doBatch();  
  39.         } catch (Exception e) {  
  40.             e.printStackTrace();  
  41.         }  
  42.   
  43.     }  
  44.   
  45. }  

上面我们处理一个含有50万记录的excel文件





读和handle只用了15秒(内存8GB,2核CPU),我们还只是开了如下的线程数和队列:


来看看读一个20万行记录以逗号“,“分隔的CSV文件 的效率吧。


这个文件的列数会多一些,也就用了20秒左右




经过我实际测试在服务器上,16GB-32GB,4-6核CPU上运行一个导入50万条数据的EXCEL至ORACLE或者是SQL SERVER也只是在5分-8分钟内的事,内存占用不过几十MB,handle线程条数也不过5-10条(等于数据库连接占用数据)。。。。。。在此我想到了07年。。。。。。我的以前有一个上家公司。。。。。。他们的一个批处理无法是读一个含有8000行,3列的txt文件导入至oracle单表,竟然要导2-4小时,有时还会OOM。。。。。。感叹中。

当然,大家可能有更好的现在的框架或者是开源的组件如:spring batch, spring cloud来更高效简单的处理这样的批处理任务,但这篇文章的目的是在于使用尽可能简单的方式让大家可以廉价高效更重要的是通过此篇我们知道了:
  1. 如何处量含有大数据量的excel文件(超过65,535行记录)
  2. BlockQueue的妙用
  3. 如何在线程任务中计算整个过程耗时的方法
笔者拿这东西写过一个按照输入关键字找含有相关内容的文本文件的搜索引擎,搜索速度比windows自带搜索快了许多,是java swing界面的,有兴趣的同鞋也可以自己去做做玩玩。

上述方案可以改进之处留给读者当回家作业吧

  1. 如果要处理的文本文件不是用逗号”,“分隔的,如何做到动态可配置Txt文件Parser时的分隔符?
  2. 如何支持多任务操作,即一个系统中对于多个不同格式的文件甚至数据库同时进行批处理,如:先启动一个100万行的txt文件的导入工作,再启动一个100万行xls文件的导入,再启动对MYSQL中一张含有100万行记录的表导入到oracle的一个表中,这样系统中有3个任务,这3个任务都是10个线程+1000个queue.size的任务,如何知道它们目前的运行情况是pending, finished还是stop or fail,甚至可以人为的去stop, suspend, restart这些批处理任务呢?
由其是第2点,处理好第2点,这个批处理导入导出框架就可以直接复用了。

下次博文将更精彩,欢迎关注。

完整代码

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值