採用POI技術進行大資料匯入
class ExcelImportUtil extends DefaultHandler {
private ExcelImportParse importExcel;
private StylesTable stylesTable;
private SharedStringsTable sst;
private String lastContents;
private boolean nextIsString;
private List<String> rowlist = new ArrayList<>();
private HashMap<Integer, String> rowMap = new HashMap<Integer, String>();
private int curRow = 0;
// private int curCol = 0;
// 定義前一個元素和當前元素的位置,用來計算其中空的單元格數量,如A6和A8等
private String preRef = null, ref = null;
// 定義該文件一行最大的單元格數,用來補全一行最後可能缺失的單元格
private String maxRef = null;
private CellDataType nextDataType = CellDataType.SSTINDEX;
private final DataFormatter formatter = new DataFormatter();
private short formatIndex;
private String formatString;
private Logger logger = LoggerFactory.getLogger(getClass());
private int sheetIndex = -1;
private Long headerIs = null;
// 用一個enum表示單元格可能的資料型別
enum CellDataType {
BOOL, ERROR, FORMULA, INLINESTR, SSTINDEX, NUMBER, DATE, NULL
}
public ExcelImportUtil(ExcelImportParse importExcel) {
this.importExcel = importExcel;
}
public void process(InputStream is,Long headerIs) throws Exception {
if (null == importExcel) {
throw new ValidationException(new ValidationError("importExcel","需要rowStrategy"));
}
this.headerIs=headerIs;
OPCPackage pkg = OPCPackage.open(is);
XSSFReader r = new XSSFReader(pkg);
stylesTable = r.getStylesTable();
SharedStringsTable sst = r.getSharedStringsTable();
XMLReader parser = fetchSheetParser(sst);
Iterator<InputStream> sheets = r.getSheetsData();
while (sheets.hasNext()) {
sheetIndex++;
InputStream sheet = sheets.next();
InputSource sheetSource = new InputSource(sheet);
parser.parse(sheetSource);
sheet.close();
}
importExcel.doService();
}
public XMLReader fetchSheetParser(SharedStringsTable sst)
throws SAXException {
XMLReader parser = XMLReaderFactory
.createXMLReader("org.apache.xerces.parsers.SAXParser");
this.sst = sst;
parser.setContentHandler(this);
return parser;
}
/**
* 解析一個element的開始時觸發事件
* @param uri
* @param localName
* @param name
* @param attributes
* @throws SAXException
*/
public void startElement(String uri, String localName, String name,
Attributes attributes) throws SAXException {
// c => cell
if (name.equals("c")) {
// 前一個單元格的位置
if (preRef == null) {
preRef = attributes.getValue("r");
} else {
preRef = ref;
}
// 當前單元格的位置
ref = attributes.getValue("r");
this.setNextDataType(attributes);
// Figure out if the value is an index in the SST
String cellType = attributes.getValue("t");
if (cellType != null && cellType.equals("s")) {
nextIsString = true;
} else {
nextIsString = false;
}
}
// Clear contents cache
lastContents = "";
}
/**
* 根據element屬性設定資料型別
*
* @param attributes
*/
public void setNextDataType(Attributes attributes) {
nextDataType = CellDataType.NUMBER;
formatIndex = -1;
formatString = null;
String cellType = attributes.getValue("t");
String cellStyleStr = attributes.getValue("s");
if ("b".equals(cellType)) {
nextDataType = CellDataType.BOOL;
} else if ("e".equals(cellType)) {
nextDataType = CellDataType.ERROR;
} else if ("inlineStr".equals(cellType)) {
nextDataType = CellDataType.INLINESTR;
} else if ("s".equals(cellType)) {
nextDataType = CellDataType.SSTINDEX;
} else if ("str".equals(cellType)) {
nextDataType = CellDataType.FORMULA;
}
if (cellStyleStr != null) {
int styleIndex = Integer.parseInt(cellStyleStr);
XSSFCellStyle style = stylesTable.getStyleAt(styleIndex);
formatIndex = style.getDataFormat();
formatString = style.getDataFormatString();
if ("m/d/yy" == formatString) {
nextDataType = CellDataType.DATE;
// full format is "yyyy-MM-dd hh:mm:ss.SSS";
formatString = "yyyy-MM-dd";
}
if (formatString == null) {
nextDataType = CellDataType.NULL;
formatString = BuiltinFormats.getBuiltinFormat(formatIndex);
}
}
}
private int getColNum(String ref) {
ref = ref.replaceAll("\\d+", "");
int num = 0;
int result = 0;
int length = ref.length();
for (int i = 0; i < length; i++) {
char ch = ref.charAt(length - i - 1);
num = (int) (ch - 'A' + 1);
num *= Math.pow(26, i);
result += num;
}
return result;
}
/**
* 解析一個element元素結束時觸發事件
* @param uri
* @param localName
* @param name
* @throws SAXException
*/
public void endElement(String uri, String localName, String name)
throws SAXException {
// Process the last contents as required.
// Do now, as characters() may be called more than once
if (nextIsString) {
int idx = Integer.parseInt(lastContents);
lastContents = new XSSFRichTextString(sst.getEntryAt(idx))
.toString();
nextIsString = false;
}
// v => contents of a cell
// Output after we've seen the string contents
if (name.equals("v")) {
String value = this.getDataValue(lastContents.trim(), "");
rowMap.put(getColNum(ref), value);
} else {
// 如果標籤名稱為 row,這說明已到行尾,呼叫 optRows() 方法
if (name.equals("row")) {
// 預設第一行為表頭,以該行單元格數目為最大數目
if (curRow == 0) {
maxRef = ref;
}
for (int i = 0; i <= getColNum(maxRef); i++) {
String val = rowMap.get(i + 1);
if (val == null) {
val = "";
}
rowlist.add(i, val);
}
//
try {
if (!rowlist.isEmpty()) {
importExcel.optRow(sheetIndex,curRow,rowlist,headerIs);
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new SAXException(e.getMessage());
}
// getRows(1, curRow, rowlist);
curRow++;
// 一行的末尾重置一些資料
rowlist.clear();
rowMap.clear();
preRef = null;
ref = null;
}
}
}
/**
* 根據資料型別獲取資料
*
* @param value
* @param thisStr
* @return
*/
public String getDataValue(String value, String thisStr)
{
switch (nextDataType) {
// 這幾個的順序不能隨便交換,交換了很可能會導致資料錯誤
case BOOL:
char first = value.charAt(0);
thisStr = first == '0' ? "FALSE" : "TRUE";
break;
case ERROR:
thisStr = "\"ERROR:" + value.toString() + '"';
break;
case FORMULA:
thisStr = '"' + value.toString() + '"';
break;
case INLINESTR:
XSSFRichTextString rtsi = new XSSFRichTextString(value.toString());
thisStr = rtsi.toString();
rtsi = null;
break;
case SSTINDEX:
String sstIndex = value.toString();
thisStr = value.toString();
break;
case NUMBER:
if (formatString != null) {
thisStr = formatter.formatRawCellContents(
Double.parseDouble(value), formatIndex, formatString)
.trim();
} else {
thisStr = value;
}
thisStr = thisStr.replace("_", "").trim();
break;
case DATE:
try {
thisStr = formatter.formatRawCellContents(
Double.parseDouble(value), formatIndex, formatString);
} catch (NumberFormatException ex) {
thisStr = value.toString();
}
thisStr = thisStr.replace(" ", "");
break;
default:
thisStr = "";
break;
}
return thisStr;
}
/**
* 獲取element的文字資料
* @param ch
* @param start
* @param length
* @throws SAXException
*/
public void characters(char[] ch, int start, int length)
throws SAXException {
lastContents += new String(ch, start, length);
}
/**
* 計算兩個單元格之間的單元格數目(同一行)
*
* @param ref
* @param preRef
* @return
*/
public int countNullCell(String ref, String preRef) {
// excel2007最大行數是1048576,最大列數是16384,最後一列列名是XFD
String xfd = ref.replaceAll("\\d+", "");
String xfd_1 = preRef.replaceAll("\\d+", "");
xfd = fillChar(xfd, 3, '@', true);
xfd_1 = fillChar(xfd_1, 3, '@', true);
char[] letter = xfd.toCharArray();
char[] letter_1 = xfd_1.toCharArray();
int res = (letter[0] - letter_1[0]) * 26 * 26
+ (letter[1] - letter_1[1]) * 26 + (letter[2] - letter_1[2]);
return res - 1;
}
/**
* 字串的填充
*
* @param str
* @param len
* @param let
* @param isPre
* @return
*/
String fillChar(String str, int len, char let, boolean isPre) {
int len_1 = str.length();
if (len_1 < len) {
if (isPre) {
for (int i = 0; i < (len - len_1); i++) {
str = let + str;
}
} else {
for (int i = 0; i < (len - len_1); i++) {
str = str + let;
}
}
}
return str;
}
public void cleanData() {
this.sheetIndex = -1;
this.rowlist = new ArrayList<>();
this.curRow = 0;
}
}
相關文章
- Springboot操作Poi進行Excel匯入Spring BootExcel
- 大資料技術之資料採集篇大資料
- 今天開始採用的十大大資料技術大資料
- Oracle使用資料泵expdp,impdp進行資料匯出匯入Oracle
- 使用Dbeaver 進行資料的匯入和匯出
- POI實現大資料EXCLE匯入匯出,解決記憶體溢位問題大資料記憶體溢位
- 解決POI大資料匯出Excel記憶體溢位、應用假死大資料Excel記憶體溢位
- 大文字資料,匯入匯出到資料庫資料庫
- 利用Java進行MySql資料庫的匯入和匯出JavaMySql資料庫
- ByteHouse實時匯入技術演進
- 大資料技術原理與應用——大資料概述大資料
- 採用importtsv匯入外部資料到hbase中ImportTTS
- SQL Server資料匯入匯出技術概述與比較(轉)SQLServer
- Poi 匯入格式轉換
- 大資料技術原理與應用大資料
- 【原創】POI匯入匯出工具類
- c# 採用datatable 快速匯入資料至MSSQL的方法分享C#SQL
- Java POI匯入Excel檔案JavaExcel
- POI匯入Excel中文API文件ExcelAPI
- 大資料技術在電商的應用大資料
- 大資料建模、分析、挖掘技術應用大資料
- Java之POI操作Excel表-匯入匯出JavaExcel
- PHP大資料xlswriter匯入匯出(最優資料化)PHP大資料
- 採用sqlldr定時將文字檔案載入進入資料庫SQL資料庫
- 大資料技術體系1(清華:大資料技術體系)大資料
- 解決POI多執行緒匯出時資料錯亂問題執行緒
- 匯入大容量資料時控制觸發器執行觸發器
- 大資料技術是如何採集到我們的資訊的呢?大資料
- 大資料技術 - Directus大資料
- 大資料技術 - Azkaban大資料
- 大資料技術 - Airflow大資料AI
- 大資料技術 - DataX大資料
- 大資料技術 - Canal大資料
- 大資料技術 - Maxwell大資料
- 大資料技術 - Phoenix大資料
- 大資料技術 - StarRocks大資料
- 大資料技術 - StreamX大資料
- 大資料技術 - Debezium大資料