xlsx和xlsm區別:
xlsm中默認啓動宏,而xlsx則是雖然帶有宏,也不會被excel執行。
寫在前頭的經驗教訓:
1,POI-3.15的Sheet.getLastRowNum()是0-based;Row.getLastColNum()結果是1-based。
2,poi中getPhysicalNumberOfRows()和getLastRowNum()區別 :
舉例說明:修改xlsx文件後綴爲rar,解壓之(xlsx是ooxml格式的文件)。找到xl\worksheets\sheet*.xml文件,打開,可以看到這是一個xml文件,這時候,如果我們在其中的sheetData元素中添加一個空的<row></row>
標籤。
getPhysicalNumberOfRows()計算的是所有的<row>
標籤的總數。
getLastRowNum()計算的是所有<row>
標籤中r屬性(行號)的最大值。
所以我們在遍歷EXCEL的時候,應該使用的遍歷行號上限(閉區間)是getLastRowNum().在這其中,可能會遇到Row==null的情況需要跳過。
另一方面,出於業務方向的考慮,我們一般要檢查row!=null的時候一行中是否全是“空白”符號,如果全是空白符號的行一般不作爲數據行分析。
3,有關格式,千萬不要試圖將那些線程不安全的對象作爲靜態常量,之前在使用jxl框架的時候,企圖將格式對象作爲全局靜態常量,最後居然在因爲線程不安全居然出現了相當摸不着頭腦的bug(第一次導出成功,之後的同一導出請求的返回數據文件很可能會被損壞)。
讀:
輔助類:
/**
* @author kingbaron
* @version 1.0
* @date 2016/12/21
* @package demo
*/
public class WorkbookFactory {
/**
* 讀取excel輸入流
* @param ips
* @return
*/
public static Workbook createWorkBook(InputStream ips){
Workbook workbook=null;
try{
workbook=getWorkBook(ips);
}catch (Exception ex){
throw new AppInternalException("打開EXCEL文件流失敗!",ex);
}
return workbook;
}
/**
* 根據excel輸入流創建WorkBook
* @param ips
* @return
* @throws java.io.IOException
*/
private static Workbook getWorkBook(InputStream ips) throws IOException {
Workbook workbook=null;
//輸入流必須支持mark/reset方法
if(!ips.markSupported()){
ips=new PushbackInputStream(ips,8);
}
//使用微軟Office文件系統,Excel2003
if(POIFSFileSystem.hasPOIFSHeader(ips)){
workbook=new HSSFWorkbook(ips);
}else if(DocumentFactoryHelper.hasOOXMLHeader(ips)){
workbook=new XSSFWorkbook(ips);
}
return workbook;
}
}
基本的業務代碼
Workbook workbook = WorkbookFactory.createWorkBook(is);
Sheet sheet = workbook.getSheetAt(0);
for(Row row:sheet){
for(Cell cell:row){
new DataFormatter().formatCellValue(cell);
}
}
寫:
輔助類:
public class ExcelWriter implements Closeable{
private OutputStream ops;
private Workbook workbook;
public ExcelWriter(OutputStream ops, ExcelType excelType) {
//使用緩衝輸出流
this.ops = new BufferedOutputStream(ops, 8192);
//創建xls或者xlsx
if (excelType.XLS.equals(excelType)) {
this.workbook = new HSSFWorkbook();
} else {
this.workbook = new XSSFWorkbook();
}
}
/**
* 將WorkBook寫到輸出流中
*
* @throws java.io.IOException
*/
public void write() throws IOException {
workbook.write(ops);
ops.close();
ops = null;
}
public Workbook getWorkbook() {
return workbook;
}
@Override
public void close() {
if (ops != null) {
try {
ops.close();
} catch (IOException ex) {
//靜默關閉
}
}
}
public enum ExcelType {
XLS("xls", "EXCEL_2003", false),
XLSX("xlsx", "EXCEL_2007", false),
XSLM("xlsm", "EXCEL_2007", true);
//文件後綴名
private String suffix;
//文件版本
private String vision;
//是否啓用宏
private boolean macros;
private ExcelType(String suffix, String vision, boolean macros) {
this.suffix = suffix;
this.vision = vision;
this.macros = macros;
}
public boolean hasMacros() {
return macros;
}
public String getSuffix() {
return suffix;
}
public String getVision() {
return vision;
}
}
}
基本業務代碼(用於Servlet中)
private ExcelWriter createExcel(HttpServletResponse response,String fileName) throws IOException {
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-disposition","attachment;filename=" +
new String(fileName.getBytes(AppGlobal.getMessageEncoding()), "ISO_8859_1"));
response.setHeader("filename", URLEncoder.encode(fileName, AppGlobal.getMessageEncoding()));
// 獲取表頭
List<ColumnOut> columns = module.getColumnsInfo(chosenCols);
ExcelWriter writer=new ExcelWriter(response.getOutputStream(), ExcelWriter.ExcelType.XLS);
Workbook wb = writer.getWorkbook();
Sheet sheet = wb.createSheet();
// 格式
CellStyle headStyle=wb.createCellStyle();
Font headFont=wb.createFont();
headFont.setFontName("ARIAL");
headFont.setFontHeightInPoints((short) 10);
headFont.setBold(true);
headStyle.setFont(headFont);
headStyle.setAlignment(HorizontalAlignment.CENTER);
//行
Row row=sheet.creatRow(0);//第0行
//單元格 A1
Cell cell=row.creatCell(0);
cell.setStyle(headStyle);//格式
cell.setValue("abc");//value