需求:
1、将EXCEL文件进行Base64位转码
2、将Base64字符串解码并解析
该方法应该适用于任何文件的转码
/**
*测试:将文件编码为base64字符串
*/
public String base64Encode() throws Exception {
// 将文件转化为输入流
String filePath = "E:\\Temp\\card.xlsx";
File file = new File(filePath);
InputStream inputStream = new FileInputStream(file);
// 将InputStream转化为byte[]
// 如果使用byte[] byte = new byte[input.available()];这种方式会出现字节码全为0的情况,原因未知
ByteArrayOutputStream bos = new ByteArrayOutputStream(1000);
byte[] b = new byte[1000];
int n;
//每次从fis读1000个长度到b中,fis中读完就会返回-1
while ((n = inputStream.read(b)) != -1)
{
bos.write(b, 0, n);
}
inputStream.close();
bos.close();
byte[] bytes = bos.toByteArray();
// 进行Base64转码
String base64Str = Base64.getEncoder().encodeToString(bytes);
return base64Str;
}
/**
* 将文件编码成的base64字符串解码为文件输入流
*/
public InputStream decode2ExcelFromBase64(String base64Str) throws Exception {
byte[] byteArray = null;
try {
// 解码为byte数组
byteArray = Base64.getDecoder().decode(base64Str);
}catch (Exception e){
throw new Exception("解码失败");
}
// 将byte数组转化为输入流
InputStream inputStream = new ByteArrayInputStream(byteArray);
return inputStream;
}
由于Excel文件有不同的版本(2003及以前的版本后缀是.xls,2007及以后的版本后缀是.xlsx)而POI对这两个版本的处理方式不同(xls文件使用HSSFWorkbook,xlsx文件使用XSSFWorkbook),所以我们需要先判断Excel的版本
WorkBook workbook = null;
//判断输入的流是否是2007以上版本,如果是则对应文件后缀应该是xlsx
if(POIXMLDocument.hasOOXMLHeader(inputStream);){
//以xlsx结尾的文件读取
workbook = new XSSFWorkbook(inputStream);
}else {
//以xls结尾的文件读取
workbook = new HSSFWorkbook(inputStream);
}
但是POIXMLDocument.hasOOXMLHeader(inputStream)方法已经弃用,我们可以采用下面的方法
// WorkbookFactory可以通过文件流直接生成合适的Workbook
Workbook workbook = WorkbookFactory.create(inputStream);
获取到Workbook后,我们就能获得其中的表sheet
//获得excel中第一个sheet
Sheet sheet = workbook.getSheetAt(0);
如果有多个sheet,我们可以通过sheet名称来获取
String sheetName = "sheet1";
Sheet sheet = workbook.getSheet(sheetName);
然后我们可以获得sheet中的每一行
// 获取指定行
Row row = sheet.getRow(0);
// 获取总行数(最后一行的行号)
int totalRowNum = sheet.getLastRowNum();
在处理xlsx文件的时候,会有一些空行(比如曾填写过数据然后删除),这些空行会被计入总行数中,但是一般情况下没有意义,还会引起异常(空行每个单元格的类型是Blank,调用取值方法时可能报空指针异常)
private boolean isBlankRow(Row row){
boolean flag = true;
// 获得行所含单元格的数量
int lastCellNum = row.getLastCellNum();
// 循环判断每个单元格,如果有数据则说明这一行不是没有意义可以略过的空行
for(int i = 0; i < lastCellNum; i++){
Cell cell = row.getCell(i);
if(cell.getCellType() != CellType.BLANK.getCode()){
flag = false;
break;
}
}
return flag;
}
private String getCellValue(Row row, int index){
String value = "";
Cell cell = row.getCell(index);
// 判断单元格的类型,如一些填写数字的单元格,只凭自己阅读单元格内容有时候
// 会判断不出单元格的类型是字符串还是数字,而调错类型方法会引起异常
if(cell.getCellType() == CellType.STRING.getCode()){
value = cell.getStringCellValue();
}else if(cell.getCellType() == CellType.NUMERIC.getCode()){
value = String.valueOf((int) cell.getNumericCellValue());
}
// 省略Boolean类型的判断以及Blank类型的处理(具体根据实际业务)
return value;
}
注:本篇文章为解决问题时的一篇随笔,不代表问题的最优解,如有错误或更好的方法欢迎指正。