使用Apache POI库在Android中操纵Excel文件
当为自定义设备上的模型处理数据或创建你的电子表格应用时,你需要知道如何操作电子表格格式的文件。在这篇文章中,我们将研究如何创建一个电子表格文件,打开它,并在其中执行常见的统计功能。
我们将模拟学生姓名和分数。由于Java不支持Excel文件格式,如果从头开始做,这个过程需要大量的代码和研究。幸运的是,我们有Apache POI库。
Apache POI是一个开源库,提供了一个Java API,用于操作基于微软的Office Open XML(OOXML)和OLE2标准的文件格式。Apache POI的发布是根据Apache许可证(V2.0)进行的。
根据定义,我们得到一个线索,这个库也可以用来操作Word和PowerPoint(幻灯片)文件格式。
Apache POI有两种格式用于操作Excel(电子表格)文件。
- 可怕的电子表格格式(HSSF)
- XML电子表格格式(XSSF)
HSSF用于.xls
格式,而XSSF用于.xlsx
格式。我们将在本教程中使用XSSF。
注意:我将交替使用Excel和Spreadsheet这两个词。
前提条件
- 对Kotlin的理解。预先接触过文件系统的工作是一个有利条件。
- 对Excel/Spreadsheets有基本了解。应该精通单元格、数值、工作簿、工作表等术语。
- 熟悉安卓开发环境和一般生态系统。虽然不是很必要,但对Gradle的工作知识可能会很有用,因为我们将使用Gradle文件添加依赖。
开始学习
在创建你的应用程序后,修改应用程序级和项目级的Gradle文件,如下所示。
应用级 build.gradle
在dependencies
部分,添加以下几行。
dependencies {
....
implementation group: 'org.apache.poi', name: 'poi-ooxml', version: '3.17'
implementation group: 'org.apache.xmlbeans', name: 'xmlbeans', version: '3.1.0'
implementation 'javax.xml.stream:stax-api:1.0'
implementation 'com.fasterxml:aalto-xml:1.2.2'
}
项目级 build.gradle
将此添加到repositories
部分。
repositories {
...
maven { url 'https://jitpack.io' }
}
构建过程完成后,我们继续在MainActivity
类中编写创建和读取Spreadsheet文件的逻辑。
存储权限
不要忘记在你的AndroidManifest
文件中添加这些权限。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
创建和添加数据到电子表格
为了实现这一目标,我们按照以下步骤进行。
- 在应用程序的目录中创建一个电子表格。
- 在电子表格中添加一个工作簿。在这一步,我们还将研究如何创建工作表。
- 为工作表创建单元格。
- 为单元格添加数据。
1.创建电子表格
我们将使用一个名为createExcelFile(ourWorkbook: Workbook)
的函数。它接受一个工作簿对象,我们将在下一步讨论。首先,我们要访问我们应用程序的目录。接下来,我们检查它是否存在。如果它不存在,我们就创建一个目录。
//get our app file directory
val ourAppFileDirectory = filesDir
//Check whether it exists or not, and create one if it does not exist.
if (ourAppFileDirectory != null && !ourAppFileDirectory.exists()) {
ourAppFileDirectory.mkdirs()
}
此后,我们创建一个名为test.xlsx
的Excel文件,并使用文件输出流将我们的工作簿写入该文件中。你可以给它一个你选择的名字。
//Create an excel file called test.xlsx
val excelFile = File(ourAppFileDirectory, "test.xlsx")
//Write a workbook to the file using a file outputstream
try {
val fileOut = FileOutputStream(excelFile)
ourWorkbook.write(fileOut)
fileOut.close()
} catch (e: FileNotFoundException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
完整的方法代码如下。
private fun createExcelFile(ourWorkbook: Workbook) {
//get our app file directory
val ourAppFileDirectory = filesDir
//Check whether it exists or not, and create one if it does not exist.
if (ourAppFileDirectory != null && !ourAppFileDirectory.exists()) {
ourAppFileDirectory.mkdirs()
}
//Create an excel file called test.xlsx
val excelFile = File(ourAppFileDirectory, "test.xlsx")
//Write a workbook to the file using a file outputstream
try {
val fileOut = FileOutputStream(excelFile)
ourWorkbook.write(fileOut)
fileOut.close()
} catch (e: FileNotFoundException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
}
2.添加一个工作簿
在这个方法中,我们从XSSFWorkbook
类中创建一个工作簿对象。一个名为statSheet的工作表被添加到工作簿中。然后调用addData()
方法,用数据填充工作表。我们将在后面看一下这个函数。
在createWorkbook()
方法执行完毕后,新创建的工作簿被返回。对于工作表的创建,使用了Apache POI的方法createSheet()
。
private fun createWorkbook(): Workbook {
// Creating a workbook object from the XSSFWorkbook() class
val ourWorkbook = XSSFWorkbook()
//Creating a sheet called "statSheet" inside the workbook and then add data to it
val sheet: Sheet = ourWorkbook.createSheet("statSheet")
addData(sheet)
return ourWorkbook
}
3.为工作表创建单元格。
有三个参数被传入。
sheetRow
- 添加数据的行。columnIndex
- 添加数值的列号。cellValue
- 要添加到单元格的值。
在createCell()
方法中,我们在传入的索引处创建一个单元格并向其添加值。该库的setCellValue(value)
方法用于向单元格添加值。
private fun createCell(sheetRow: Row, columnIndex: Int, cellValue: String?) {
//create a cell at a passed in index
val ourCell = sheetRow.createCell(columnIndex)
//add the value to it
//a cell can be empty. That's why its nullable
ourCell?.setCellValue(cellValue)
}
4.向单元格中添加数据
这个方法很简单。我们在作为参数传入的工作表中创建行并向其添加数据。
private fun addData(sheet: Sheet) {
//Creating rows at passed in indices
val row1 = sheet.createRow(0)
val row2 = sheet.createRow(1)
val row3 = sheet.createRow(2)
val row4 = sheet.createRow(3)
val row5 = sheet.createRow(4)
val row6 = sheet.createRow(5)
val row7 = sheet.createRow(6)
//Adding data to each cell
createCell(row1, 0, "Mike")
createCell(row1, 1, "470")
createCell(row2, 0, "Montessori")
createCell(row2, 1, "460")
createCell(row3, 0, "Sandra")
createCell(row3, 1, "380")
createCell(row4, 0, "Moringa")
createCell(row4, 1, "300")
createCell(row5, 0, "Torres")
createCell(row5, 1, "270")
createCell(row6, 0, "McGee")
createCell(row6, 1, "420")
createCell(row7, 0, "Gibbs")
createCell(row7, 1, "510")
}
读取Excel文件并执行统计计算
就像创建和填充数据到电子表格一样,我们将遵循以下步骤。
- 从应用程序的目录中检索Excel文件。
- 检索工作簿。
- 选择我们要处理的工作表。
- 对数据进行统计计算。
1.检索Excel文件
我们使用一个叫做getExcelFile()
的函数。在let
范围内,我们检查文件是否存在,如果存在则返回。该函数可能会返回null,因为文件可能不存在。这就是为什么它被做成nullable。
private fun getExcelFile(): File? {
val ourAppFileDirectory = filesDir
ourAppFileDirectory?.let {
//Check if file exists or not
if (it.exists()) {
//check the file in the directory called "test.xlsx"
var retrievedExcel = File(ourAppFileDirectory, "test.xlsx")
//return the file
return retrievedExcel
}
}
return null
}
2.检索工作簿
这里,我们从加载的电子表格中读取工作簿作为输入流,然后返回工作簿。
private fun retrieveWorkbook(): Workbook? {
//Reading the workbook from the loaded spreadsheet file
getExcelFile()?.let {
try {
//Reading it as stream
val workbookStream = FileInputStream(it)
//Return the loaded workbook
return WorkbookFactory.create(workbookStream)
} catch (e: Exception) {
e.printStackTrace()
}
}
//the workbook may not exist
return null
}
3.选择工作表
我们使用库中的getSheetAt(position)
方法来完成这个任务。选择之后,我们返回它。由于工作表可能不存在,这个方法可能返回一个空值。
private fun selectSheet(): Sheet? {
//choosing the workbook
retrieveWorkbook()?.let { workbook ->
//Checking the existence of a sheet
if (workbook.numberOfSheets > 0) {
//Return the first sheet
return workbook.getSheetAt(0)
}
}
return null
}
执行统计计算
要完成三个基本的统计功能。
- 平均数
- 方差
- 标准偏差
让我们来看看它们。
1.平均数
我们将所有的数值相加,然后用总数值除以学生人数。一个数组作为参数传入,我们将从中获得这些值。
private fun findMean(arrayArg: Array<Int>): Double {
var total = 0.0
var i = 0
for (a in arrayArg) {
total += arrayArg[i]
i++
}
var avg = total / arrayArg.size
return avg
}
2.方差
与平均值的平方差。然后,逻辑将从平均值中减去每个值,将其平方化,然后找到一个平均值。因此,我们的函数将有两个参数,数值数组和平均值。
private fun findVariance(arrayArg: Array<Int>, mean: Double): Double {
var indexVariance = 0.0
var i = 0
for (a in arrayArg) {
indexVariance += Math.pow(((arrayArg[i].toDouble()) - mean), 2.0)
i++
}
var avgVariance = indexVariance / arrayArg.size
return avgVariance
}
3.标准变异
这就是方差的平方根。
var stdDeviation: Double = Math.sqrt(variance)
Apache POI库还提供内置的Excel函数,如SUMIF、COUNTIF等。
输出
运行该应用程序后,我们应该得到以下输出。
该Excel文件将类似于下面的文件。
你可以通过IDE在设备资源管理器中访问该Excel文件,具体步骤如下。视图->工具窗口->设备文件资源管理器->数据>你的包-名称->文件。
总结
在本教程中,我们研究了创建Excel文件,读取文件,以及对文件中的数据执行常见的统计功能。我希望你觉得这篇文章很有见地。你可以自定义代码,并利用它做更多事情。例如,你可以添加动态输入,为Excel文件中的数据创建回收器适配器,等等。