需求:
1、将EXCEL文件进行Base64位转码
2、将Base64字符串解码并解析
1. 将Excel文件进行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中读完就会返回-1while ((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;
}
2. 进行Base64解码
/** * 将文件编码成的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;
}
3. POI解析Excel文件(输入流InputStream)
3.1 工作簿Workbook
由于Excel文件有不同的版本(2003及以前的版本后缀是.xls,2007及以后的版本后缀是.xlsx)而POI对这两个版本的处理方式不同(xls文件使用HSSFWorkbook,xlsx文件使用XSSFWorkbook),所以我们需要先判断Excel的版本
3.1.1 手动判断,然后调用不同的Workbook
WorkBook workbook = null;//判断输入的流是否是2007以上版本,如果是则对应文件后缀应该是xlsx
if(POIXMLDocument.hasOOXMLHeader(inputStream);){//以xlsx结尾的文件读取workbook = new XSSFWorkbook(inputStream);
}else {//以xls结尾的文件读取workbook = new HSSFWorkbook(inputStream);
}
但是POIXMLDocument.hasOOXMLHeader(inputStream)方法已经弃用,我们可以采用下面的方法
3.1.2 使用WorkbookFactory
// WorkbookFactory可以通过文件流直接生成合适的Workbook
Workbook workbook = WorkbookFactory.create(inputStream);
3.2 Sheet、Row
获取到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();
3.2.1 空行判断
在处理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;
}
3.2.2 获取单元格值
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;}
注:本篇文章为解决问题时的一篇随笔,不代表问题的最优解,如有错误或更好的方法欢迎指正。