前言:
在Android中,对于excel文件无法进行直接展示,只能通过其他方式进行间接展示,免费的相对来说比较复杂,如果只是个人使用的话或者可支持付费商用使用的话,推荐使用 Aspose.Cells进行实现,如果是简单的表格可以使用 POI+itext的形式进行实现
1、POI依赖
导入完整的POI库的依赖:
implementation 'org.apache.poi:poi:5.2.3'
implementation 'org.apache.poi:poi-ooxml:5.2.3'
POI库中数据过于多,所以我用的是简化版的
下载 android5xlsx 项目中两个jar包放在自己文件的libs路径下,比添加依赖
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar', '*.so'])
2、iText的依赖
implementation "com.itextpdf:itextpdf:5.5.13"
3、将excel文件转为PDF文件
3.1 判断是否为xls和xlsx文件
/**
* 根据类型后缀名简单判断是否Excel文件
* @param file 文件
* @return 是否Excel文件
*/
private fun checkIfExcelFile(file: File?): Boolean {
if (file == null) {
return false
}
val name = file.name
//”.“ 需要转义字符
val list = name.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()
//划分后的小于2个元素说明不可获取类型名
if (list.size < 2) {
return false
}
val typeName = list[list.size - 1]
//满足xls或者xlsx才可以
return "xls" == typeName || "xlsx" == typeName
}
3.2 将excel文件转为pdf文件
将excel文件中的单元格中字符进行循环遍历,写入到生成的pdf文件中,并对其展示效果进行处理。
/**
* 将excel文件转为Pdf文件
* @param excelName 文件名称(带文件后缀)
* @param path 文件存放路径
* @param pdfName 转换后的文件名称
*/
fun convertExcelToPdf(context: Context, excelName: String, path: String, pdfName: String) {
if (!checkIfExcelFile(File("$path/$excelName"))) return
var document: Document? = null
var writer: PdfWriter? = null
var workbook: Workbook? = null
var fontStream: InputStream? = null
val pdfFile = File(path, pdfName)
try {
// ==================== 1. 文件路径有效性校验 ====================
val excelFile = File("$path/$excelName")
if (!excelFile.exists()) {
throw FileNotFoundException("Excel文件不存在: ${excelFile.absolutePath}")
}
// ==================== 2. 安全初始化PDF文档 ====================
document = Document(PageSize.A4.rotate()) // 改用A4横向以适应表格
writer = PdfWriter.getInstance(document, FileOutputStream(pdfFile))
document.open()
// ==================== 3. 字体加载优化 ====================
fontStream = try {
context.assets.open("fonts/$ttfName")
} catch (e: Exception) {
throw IOException("字体文件加载失败: ${e.message}")
}
val fontBytes = fontStream.use { it?.readBytes() }
val chineseFont = BaseFont.createFont(
ttfName, // 必须包含文件后缀
BaseFont.IDENTITY_H,
BaseFont.EMBEDDED,
true,
fontBytes,
null
)
// ==================== 4. 表格样式优化 ====================
workbook = WorkbookFactory.create(excelFile)
val sheet = workbook.getSheetAt(0)
// 添加标题(带错误处理)
val titleFont = Font(chineseFont, 14f, Font.BOLD)
val title = Paragraph(sheet.sheetName, titleFont).apply {
alignment = Element.ALIGN_CENTER
spacingAfter = 20f // 添加标题与表格间距
}
document.add(title)
// 动态计算列宽(首行作为表头)
val headerRow = sheet.getRow(0)
val columnWidths = FloatArray(headerRow.lastCellNum.toInt()) { 1f }
val table = PdfPTable(columnWidths).apply {
headerRows = 1
widthPercentage = 100f
setWidths(columnWidths)
}
// ==================== 5. 数据填充优化 ====================
for (row in sheet) {
for (cell in row) {
val cellContent = getCellValue(cell)
val cellFont = if (cell.rowIndex == 0) {
Font(chineseFont, 12f, Font.BOLD, BaseColor.WHITE)
} else {
Font(chineseFont, 10f)
}
PdfPCell(Phrase(cellContent, cellFont)).apply {
borderWidth = 0.1f
borderColor = BaseColor.DARK_GRAY
paddingRight = 15f
paddingTop = 15f
paddingLeft = 15f
paddingBottom = 15f
horizontalAlignment = Element.ALIGN_CENTER
verticalAlignment = Element.ALIGN_MIDDLE
if (cell.rowIndex == 0) {
backgroundColor = BaseColor(79, 129, 189) // 专业蓝色表头
}
}.also { table.addCell(it) }
}
}
// ==================== 6. 强制刷新缓冲区 ====================
document.add(table)
document.close()
document = null // 防止重复关闭
// 验证PDF文件生成结果
if (!pdfFile.exists() || pdfFile.length() == 0L) {
throw IOException("PDF文件生成失败")
}
} catch (e: Exception) {
// ==================== 7. 增强错误处理 ====================
Log.e("PDF生成", "错误信息: ${e.message}", e)
pdfFile.delete() // 删除无效文件
throw e
} finally {
// ==================== 8. 安全释放资源 ====================
val resourseList = mutableListOf( document to { document?.close() },
writer to { writer?.close() },
workbook to { workbook?.close() },
fontStream to { fontStream?.close() })
resourseList.forEach { (resource, closer) ->
try {
closer
} catch (e: Exception) {
Log.w("ResourceClose", "资源释放失败", e)
}
}
}
}
/**
* 辅助函数:获取单元格值(处理空单元格)
*
*/
private fun getCellValue(cell: Cell): String {
Logd.t("获取单元格中的数值 ${cell}")
return when {
cell.cellType == Cell.CELL_TYPE_STRING -> cell.stringCellValue
cell.cellType == Cell.CELL_TYPE_NUMERIC -> DataFormatter().formatCellValue(cell)
else -> cell.toString()
}
}
尾声
上述方法只能用于简单的表格转换,对于复杂的表格转换会出现格式错乱的效果