xls與xlsx的區(qū)別:
- .xls是03版Office Microsoft Office Excel 工作表的格式,能被所有的office程序打開
- .xlsx是07版Office Microsoft Office Excel 工作表的格式,只能用2007office以上的版本打開?;赬ML的壓縮文件格式取代了其目前專有的默認(rèn)文件格式,在傳統(tǒng)的文件名擴(kuò)展名后面添加了字母x(即.docx取代.doc、.xlsx取代.xls,等等),使其占用空間更小。
說明
1.對于 .xls 格式 sheet1 的第1行、第1列命名為 s1_row1_col1_xls
2.代碼中存儲Excel數(shù)據(jù)的格式為<sheetName,從左到右、從上到下二維數(shù)組>的形式
本文使用到的Jar包、Excel文件以及源碼:傳送門
個人博客
一、jxl解析xls格式Excel
由于是直接調(diào)用API所以這里直接上代碼
部分代碼:
fun xlsJxl(file: File): Map<String, List<List<String>>> {
val result = ArrayMap<String, List<List<String>>>()
Workbook.getWorkbook(file).sheets.forEach { sheet ->
val rowsList = ArrayList<List<String>>()//列數(shù)據(jù)
val sheetName = sheet.name
for (i in 0 until sheet.rows) {
rowsList.add(
sheet.getRow(i).map { it.contents }
)
}
result[sheetName] = rowsList
}
return result
}
xls格式Excel文件sheet1內(nèi)容:

xls格式Excel文件sheet2內(nèi)容:

xls格式Excel文件sheet3內(nèi)容:

運行結(jié)果:

二、個人理解分析xlsx格式Excel(無法在項目中使用)
由于jxl無法解析xlsx,所以必須另辟蹊徑,在開頭提過,xlsx格式是基于XML文件來生成的,所以我們將.xls的后綴改為.zip并將其進(jìn)行解壓。我們將會看到以下的目錄結(jié)構(gòu):
xlsx解壓的根目錄:

xlsx解壓根目錄下的xl:

xlsx解壓根目錄下的xl/worksheets:

我們要使用的文件是sharedStrings.xml文件(里面存在Excel中的數(shù)據(jù))、sheet1.xml、sheet2.xml、sheet3.xml。下面通過分析sheet文件與sharedStrings的找到它們的對應(yīng)關(guān)系:
xlsx格式Excel文件sheet1內(nèi)容:

xlsx格式Excel文件sheet2內(nèi)容:

xlsx格式Excel文件sheet3內(nèi)容:

sharedStrings.xml內(nèi)容:

sheet1.xml內(nèi)容:

對應(yīng)關(guān)系:

注意在sharedString.xml上面截圖做記號的紅色框框(從0-35的序號只是為了好理解補充的,實際上里面是不存在的)。從 最后一張圖中可以很好的看出 sheet1.xml與sharedString.xml的對應(yīng)關(guān)系,即sheet1中 " v " 標(biāo)簽里的數(shù)字為sharedString中的索引, " row " 標(biāo)簽為行。所以我們只要解析xml讀取出sharedString中的數(shù)據(jù),每個sheet按行讀取索引來整理數(shù)據(jù)
部分代碼:
fun xlsxSelf(file: File): Map<String, List<List<String>>> {
val result = ArrayMap<String, List<List<String>>>()
//獲取所有元素
val zipFile = ZipFile(file)
val cellsList = ArrayList<String>()
val xmlPullParser = Xml.newPullParser()
zipFile.getInputStream(zipFile.getEntry("xl/sharedStrings.xml"))
.use { inputStream ->
xmlPullParser.setInput(inputStream, "utf-8")
var eventType = xmlPullParser.eventType
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG && xmlPullParser.name == "t") {
cellsList.add(xmlPullParser.nextText())
}
eventType = xmlPullParser.next()
}
}
//獲取cell對應(yīng)的index,并添加到Map中保存
file.inputStream().use { inputStream ->
ZipInputStream(inputStream).use { zis ->
var zipDir: ZipEntry? = null
while ({ zipDir = zis.nextEntry;zipDir }() != null) {
if (zipDir!!.name.startsWith("xl/worksheets/", true) &&
zipDir!!.name.endsWith("xml", true)
) {
val rowsList = ArrayList<List<String>>()
zipFile.getInputStream(zipFile.getEntry(zipDir!!.name))
.use { inputStream ->
xmlPullParser.setInput(inputStream, "utf-8")
val itemList: ArrayList<String> = ArrayList()//用于保存每行的數(shù)據(jù)
var eventType = xmlPullParser.eventType
while (eventType != XmlPullParser.END_DOCUMENT) {
when (eventType) {
XmlPullParser.START_TAG -> {
if (xmlPullParser.name == "row") {
itemList.clear()//每行數(shù)據(jù)開始清空容器
} else if (xmlPullParser.name == "v") {
val index = xmlPullParser.nextText()
itemList.add(cellsList[index.toInt()])
}
}
XmlPullParser.END_TAG -> {
if (xmlPullParser.name == "row") {
//將行數(shù)據(jù)保存
rowsList.add(itemList.toList())
}
}
}
eventType = xmlPullParser.next()
}
//
result[zipDir!!.name.sheetName()] = rowsList
}
}
}
}
}
return result
}
運行結(jié)果:

問題:這只實現(xiàn)了簡單解析 .xlsx 格式的 Excel。其中還存在一些問題未解決,無法獲得到重命名的sheet的名字,即,解壓得到sheet都是按sheet1,sheet2,sheet3命名的。我分析解壓的xml后,還無法找到sheet名字的對應(yīng)關(guān)系。還有一些關(guān)于格式不同也會導(dǎo)致解析問題,總的來說還需要對文件進(jìn)行進(jìn)一步的分析。所以上面的方法無法使用在正式項目中。
三、POI解析xls/xlsx格式Excel(可應(yīng)用于項目中)
The Apache POI distribution consists of support for many document file formats. This support is provided in several Jar files. Not all of the Jars are needed for every format. The following tables show the relationships between POI components, Maven repository tags, and the project's Jar files.
Apache POI發(fā)行版支持多種文檔文件格式。這種支持是在幾個Jar文件中提供的。并不是每種格式都需要所有的jar。下表顯示了POI組件、Maven存儲庫標(biāo)記和項目Jar文件之間的關(guān)系。

- HSSF是我們將Microsoft Excel 97(-2003)文件格式(BIFF8)移植到純Java的端口 -> xls格式
- XSSF是Microsoft Excel XML(2007+)文件格式(OOXML)到純Java的移植 -> xlsx格式
從上面表格中可以看出我們要解析Excel的xls、xlsx需要導(dǎo)入poi與poi-ooxml的jar包,但是由于Android直接引用POI的jar在解析xlsx格式Excel時會出現(xiàn)錯誤,這里我使用之前在Github找到的經(jīng)過修改后的jar包(但是過挺久的了所以找不到原項目了。詳情請查看源碼)
部分代碼:
fun excelPOI(file: File): Map<String, List<List<String>>> {
val result = ArrayMap<String, List<List<String>>>()
WorkbookFactory.create(file).use { workBook ->
for (sheetIndex in 0 until workBook.numberOfSheets) {
val rowsList = ArrayList<List<String>>()
val sheet = workBook.getSheetAt(sheetIndex)
sheet.rowIterator()
.forEach { row ->
val itemList: ArrayList<String> = ArrayList()//用于保存每行的數(shù)據(jù)
row.cellIterator().forEach { cell ->
itemList.add(cell.stringCellValue)
}
rowsList.add(itemList)
}
result[sheet.sheetName] = rowsList
}
}
return result
}
POI不僅可以操作Excel,也可以操作其他Office文檔,而且功能特別強大。本文只展示了POI解析Excel中內(nèi)容的功能,更多功能請查看官方文檔。