User-Profile-Image
hankin
  • 5
  • Java
  • Kotlin
  • Spring
  • Web
  • SQL
  • MegaData
  • More
  • Experience
  • Enamiĝu al vi
  • 分类
    • Zuul
    • Zookeeper
    • XML
    • WebSocket
    • Web Notes
    • Web
    • Vue
    • Thymeleaf
    • SQL Server
    • SQL Notes
    • SQL
    • SpringSecurity
    • SpringMVC
    • SpringJPA
    • SpringCloud
    • SpringBoot
    • Spring Notes
    • Spring
    • Servlet
    • Ribbon
    • Redis
    • RabbitMQ
    • Python
    • PostgreSQL
    • OAuth2
    • NOSQL
    • Netty
    • MySQL
    • MyBatis
    • More
    • MinIO
    • MegaData
    • Maven
    • LoadBalancer
    • Kotlin Notes
    • Kotlin
    • Kafka
    • jQuery
    • JavaScript
    • Java Notes
    • Java
    • Hystrix
    • Git
    • Gateway
    • Freemarker
    • Feign
    • Eureka
    • ElasticSearch
    • Docker
    • Consul
    • Ajax
    • ActiveMQ
  • 页面
    • 归档
    • 摘要
    • 杂图
    • 问题随笔
  • 友链
    • Spring Cloud Alibaba
    • Spring Cloud Alibaba - 指南
    • Spring Cloud
    • Nacos
    • Docker
    • ElasticSearch
    • Kotlin中文版
    • Kotlin易百
    • KotlinWeb3
    • KotlinNhooo
    • 前端开源搜索
    • Ktorm ORM
    • Ktorm-KSP
    • Ebean ORM
    • Maven
    • 江南一点雨
    • 江南国际站
    • 设计模式
    • 熊猫大佬
    • java学习
    • kotlin函数查询
    • Istio 服务网格
    • istio
    • Ktor 异步 Web 框架
    • PostGis
    • kuangstudy
    • 源码地图
    • it教程吧
    • Arthas-JVM调优
    • Electron
    • bugstack虫洞栈
    • github大佬宝典
    • Sa-Token
    • 前端技术胖
    • bennyhuo-Kt大佬
    • Rickiyang博客
    • 李大辉大佬博客
    • KOIN
    • SQLDelight
    • Exposed-Kt-ORM
    • Javalin—Web 框架
    • http4k—HTTP包
    • 爱威尔大佬
    • 小土豆
    • 小胖哥安全框架
    • 负雪明烛刷题
    • Kotlin-FP-Arrow
    • Lua参考手册
    • 美团文章
    • Java 全栈知识体系
    • 尼恩架构师学习
    • 现代 JavaScript 教程
    • GO相关文档
    • Go学习导航
    • GoCN社区
    • GO极客兔兔-案例
    • 讯飞星火GPT
    • Hollis博客
    • PostgreSQL德哥
    • 优质博客推荐
    • 半兽人大佬
    • 系列教程
    • PostgreSQL文章
    • 云原生资料库
    • 并发博客大佬
Help?

Please contact us on our email for need any support

Support
    首页   ›   Java   ›   Java Notes   ›   正文
Java Notes

Java—POI操作Excel

2020-05-09 12:02:21
1918  0 0

阅读完需:约 11 分钟

一、POI概述

Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能。  

结构:

  • HSSF - 提供读写Microsoft Excel格式档案的功能。
  • XSSF - 提供读写Microsoft Excel OOXML格式档案的功能。
  • SXSSF:是在XSSF基础上,POI3.8版本开始提供的支持低内存占用的操作方式,扩展名为.xlsx。
  • HWPF - 提供读写Microsoft Word格式档案的功能。
  • HSLF - 提供读写Microsoft PowerPoint格式档案的功能。
  • HDGF - 提供读写Microsoft Visio格式档案的功能。

  使用必须引入依赖

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.17</version>
</dependency>

二、HSSF概况

  HSSF 是Horrible SpreadSheet Format的缩写,通过HSSF,你可以用纯Java代码来读取、写入、修改Excel文件。HSSF 为读取操作提供了两类API:usermodel和eventusermodel,即“用户模型”和“事件-用户模型”。

三、 POI EXCEL文档结构类

  • HSSFWorkbook excel文档对象
  • HSSFSheet excel的sheet
  • HSSFRow excel的行
  • HSSFCell excel的单元格
  • HSSFFont excel字体
  • HSSFName 名称
  • HSSFDataFormat 日期格式
  • HSSFHeader sheet头
  • HSSFFooter sheet尾
  • HSSFCellStyle cell样式
  • HSSFDateUtil 日期
  • HSSFPrintSetup 打印
  • HSSFErrorConstants 错误信息表

四、EXCEL的读写操作

1、读取“区域数据.xls”并储存于list集合中,“区域数据.xls”如下图

public List<Area> importXLS(){

    ArrayList<Area> list = new ArrayList<>();
    try {
     //1、获取文件输入流
     InputStream inputStream = new FileInputStream("/Users/Shared/区域数据.xls");
     //2、获取Excel工作簿对象
        HSSFWorkbook workbook = new HSSFWorkbook(inputStream);
     //3、得到Excel工作表对象
        HSSFSheet sheetAt = workbook.getSheetAt(0);
        //4、循环读取表格数据
     for (Row row : sheetAt) {
       //首行(即表头)不读取
            if (row.getRowNum() == 0) {
                continue;
            }
            //读取当前行中单元格数据,索引从0开始
       String areaNum = row.getCell(0).getStringCellValue(); 
            String province = row.getCell(1).getStringCellValue();
            String city = row.getCell(2).getStringCellValue();
            String district = row.getCell(3).getStringCellValue();
            String postcode = row.getCell(4).getStringCellValue();

            Area area = new Area();
            area.setCity(city);
            area.setDistrict(district);
            area.setProvince(province);
       area.setPostCode(postcode);
            list.add(area);
        }
     //5、关闭流
        workbook.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
  return list;
}

2、导出数据到“区域数据.xls”文件中,页面数据如下图:

public void exportExcel() throws IOException {

        Page<Area> page = areaService.pageQuery(null);
        List<Area> list = page.getContent();

        //1.在内存中创建一个excel文件
        HSSFWorkbook hssfWorkbook = new HSSFWorkbook();
        //2.创建工作簿
        HSSFSheet sheet = hssfWorkbook.createSheet();
        //3.创建标题行
        HSSFRow titlerRow = sheet.createRow(0);
        titlerRow.createCell(0).setCellValue("省");
        titlerRow.createCell(1).setCellValue("市");
        titlerRow.createCell(2).setCellValue("区");
        titlerRow.createCell(3).setCellValue("邮编");
        titlerRow.createCell(4).setCellValue("简码");
        titlerRow.createCell(5).setCellValue("城市编码");

        //4.遍历数据,创建数据行
        for (Area area : list) {
            //获取最后一行的行号
            int lastRowNum = sheet.getLastRowNum();
            HSSFRow dataRow = sheet.createRow(lastRowNum + 1);
            dataRow.createCell(0).setCellValue(area.getProvince());
            dataRow.createCell(1).setCellValue(area.getCity());
            dataRow.createCell(2).setCellValue(area.getDistrict());
            dataRow.createCell(3).setCellValue(area.getPostcode());
            dataRow.createCell(4).setCellValue(area.getShortcode());
            dataRow.createCell(5).setCellValue(area.getCitycode());
        }
        //5.创建文件名
        String fileName = "区域数据统计.xls";
        //6.获取输出流对象
        HttpServletResponse response = ServletActionContext.getResponse();
        ServletOutputStream outputStream = response.getOutputStream();

        //7.获取mimeType
        ServletContext servletContext = ServletActionContext.getServletContext();
        String mimeType = servletContext.getMimeType(fileName);
        //8.获取浏览器信息,对文件名进行重新编码
        HttpServletRequest request = ServletActionContext.getRequest();
        fileName = FileUtils.filenameEncoding(fileName, request);

        //9.设置信息头
        response.setContentType(mimeType);
        response.setHeader("Content-Disposition","attachment;filename="+fileName);
        //10.写出文件,关闭流
        hssfWorkbook.write(outputStream);
        hssfWorkbook.close();
    }

工具类

public class FileUtils {

    public static String filenameEncoding(String filename, HttpServletRequest request) throws IOException {
        String agent = request.getHeader("User-Agent"); //获取浏览器
        if (agent.contains("Firefox")) {
            BASE64Encoder base64Encoder = new BASE64Encoder();
            filename = "=?utf-8?B?"
                    + base64Encoder.encode(filename.getBytes("utf-8"))
                    + "?=";
        } else if(agent.contains("MSIE")) {
            filename = URLEncoder.encode(filename, "utf-8");
        } else if(agent.contains ("Safari")) {
            filename = new String (filename.getBytes ("utf-8"),"ISO8859-1");
        } else {
            filename = URLEncoder.encode(filename, "utf-8");
        }
        return filename;
    }
}

 写出xls文件:

五、 EXCEL常用操作方法

1、 得到Excel常用对象

POIFSFileSystem fs=newPOIFSFileSystem(new FileInputStream("d:/test.xls")); 
//得到Excel工作簿对象 
HSSFWorkbook wb = new HSSFWorkbook(fs); 
//得到Excel工作表对象 
HSSFSheet sheet = wb.getSheetAt(0); 
//得到Excel工作表的行 
HSSFRow row = sheet.getRow(i); 
//得到Excel工作表指定行的单元格 
HSSFCell cell = row.getCell((short) j); 
cellStyle = cell.getCellStyle();//得到单元格样式

2、建立Excel常用对象

HSSFWorkbook wb = new HSSFWorkbook();//创建Excel工作簿对象 
HSSFSheet sheet = wb.createSheet("new sheet");//创建Excel工作表对象 
HSSFRow row = sheet.createRow((short)0); //创建Excel工作表的行 
cellStyle = wb.createCellStyle();//创建单元格样式 
row.createCell((short)0).setCellStyle(cellStyle); //创建Excel工作表指定行的单元格 
row.createCell((short)0).setCellValue(1); //设置Excel工作表的值

3、设置sheet名称和单元格内容

wb.setSheetName(1, "第一张工作表",HSSFCell.ENCODING_UTF_16); 
cell.setEncoding((short) 1); 
cell.setCellValue("单元格内容");

4、取得sheet的数目

wb.getNumberOfSheets()

5、 根据index取得sheet对象

HSSFSheet sheet = wb.getSheetAt(0);

6、取得有效的行数

int rowcount = sheet.getLastRowNum();

7、取得一行的有效单元格个数

row.getLastCellNum();

8、单元格值类型读写

cell.setCellType(HSSFCell.CELL_TYPE_STRING); //设置单元格为STRING类型 
cell.getNumericCellValue();//读取为数值类型的单元格内容 

9、设置列宽、行高

sheet.setColumnWidth((short)column,(short)width); 
row.setHeight((short)height);

10、添加区域,合并单元格

Region region = new Region((short)rowFrom,(short)columnFrom,(short)rowTo 
,(short)columnTo);//合并从第rowFrom行columnFrom列 
sheet.addMergedRegion(region);// 到rowTo行columnTo的区域 
//得到所有区域 
sheet.getNumMergedRegions() 

11、保存Excel文件

FileOutputStream fileOut = new FileOutputStream(path); 
wb.write(fileOut);

12、根据单元格不同属性返回字符串数值

public String getCellStringValue(HSSFCell cell) { 
  String cellValue = ""; 
  switch (cell.getCellType()) { 
    case HSSFCell.CELL_TYPE_STRING://字符串类型 
        cellValue = cell.getStringCellValue(); 
        if(cellValue.trim().equals("")||cellValue.trim().length()<=0) 
          cellValue=" "; 
        break; 
    case HSSFCell.CELL_TYPE_NUMERIC: //数值类型 
        cellValue = String.valueOf(cell.getNumericCellValue()); 
        break; 
    case HSSFCell.CELL_TYPE_FORMULA: //公式 
        cell.setCellType(HSSFCell.CELL_TYPE_NUMERIC); 
        cellValue = String.valueOf(cell.getNumericCellValue()); 
        break; 
    case HSSFCell.CELL_TYPE_BLANK: 
        cellValue=" "; 
        break; 
    case HSSFCell.CELL_TYPE_BOOLEAN: 
        break; 
    case HSSFCell.CELL_TYPE_ERROR: 
        break; 
    default: 
        break; 
  } 
  return cellValue; 
}

13、常用单元格边框格式

HSSFCellStyle style = wb.createCellStyle(); 
style.setBorderBottom(HSSFCellStyle.BORDER_DOTTED);//下边框 
style.setBorderLeft(HSSFCellStyle.BORDER_DOTTED);//左边框 
style.setBorderRight(HSSFCellStyle.BORDER_THIN);//右边框 
style.setBorderTop(HSSFCellStyle.BORDER_THIN);//上边框

14、设置字体和内容位置

HSSFFont f = wb.createFont(); 
f.setFontHeightInPoints((short) 11);//字号 
f.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);//加粗 
style.setFont(f); 
style.setAlignment(HSSFCellStyle.ALIGN_CENTER);//左右居中 
style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//上下居中 
style.setRotation(short rotation);//单元格内容的旋转的角度 
HSSFDataFormat df = wb.createDataFormat(); 
style1.setDataFormat(df.getFormat("0.00%"));//设置单元格数据格式 
cell.setCellFormula(string);//给单元格设公式 
style.setRotation(short rotation);//单元格内容的旋转的角度

15、插入图片

//先把读进来的图片放到一个ByteArrayOutputStream中,以便产生ByteArray 
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream(); 
BufferedImage bufferImg = ImageIO.read(new File("ok.jpg")); 
ImageIO.write(bufferImg,"jpg",byteArrayOut); 
//读进一个excel模版 
FileInputStream fos = new FileInputStream(filePathName+"/stencil.xlt"); 
fs = new POIFSFileSystem(fos); 
//创建一个工作薄 
HSSFWorkbook wb = new HSSFWorkbook(fs); 
HSSFSheet sheet = wb.getSheetAt(0); 
HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); 
HSSFClientAnchor anchor = new HSSFClientAnchor(0,0,1023,255,(short) 0,0,(short)10,10); 
patriarch.createPicture(anchor , wb.addPicture(byteArrayOut.toByteArray(),HSSFWorkbook.PICTURE_TYPE_JPEG));

16、调整工作表位置

HSSFWorkbook wb = new HSSFWorkbook(); 
HSSFSheet sheet = wb.createSheet("format sheet"); 
HSSFPrintSetup ps = sheet.getPrintSetup(); 
sheet.setAutobreaks(true); 
ps.setFitHeight((short)1); 
ps.setFitWidth((short)1);

例子:

写入一个Excel

public class ExcelWriter {
    //先要有个路劲
    static String path="F:\\demo\\javapoi\\demopoi\\";
    public static void main(String[] args) throws IOException {
        //1,创建一个工作薄
        Workbook wordkbook =new HSSFWorkbook();
        //表名
        Sheet sheet=wordkbook.createSheet("灰灰统计表");
        //创建行
        Row row1=sheet.createRow(0);
        //4.创建一个单元格
        Cell cell = row1.createCell(0);
        cell.setCellValue("今日新增观众");
        Cell cell2 = row1.createCell(1);
        cell2.setCellValue("卢本伟");

        //创建行
        Row row2=sheet.createRow(1);
        //4.创建一个单元格
        Cell cell3 = row2.createCell(0);
        cell3.setCellValue("统计时间");
        Cell cell24= row2.createCell(1);
        String time=new DateTime().toString("yyyy-MM-dd HH:mm:ss");
        cell24.setCellValue(time);

        //生成一张表 03是xls 07是xlsx
        FileOutputStream fileOutputStream = new FileOutputStream(path + "灰灰统计表07.xlsx");
       wordkbook.write(fileOutputStream);

       fileOutputStream.close();
        System.out.println("灰灰统计表03已生成");
    }
}

上面写完后会在项目目录下生成一个表格

读取我们所写的表格

这个操作跟上述的写并没有什么不同,不同就是方法是get而不是set

static String path="F:\\demo\\javapoi\\demopoi";
    @Test
    public void testread03() throws IOException {


        //Sheet sheet=workbook.createSheet("统计表");
        //sheet操作表中元素
        FileInputStream fileInputStream = new FileInputStream(path + "灰灰统计表03.xls");
        Workbook workbook=new HSSFWorkbook(fileInputStream);
        Sheet sheet = workbook.getSheetAt(0);
        Sheet sheet2 = workbook.getSheet("灰灰统计表");
        Row row = sheet.getRow(1);
        Cell cell = row.getCell(0);
        Cell cell2 = row.getCell(1);
        System.out.println(cell.getStringCellValue());
        System.out.println(cell2.getNumericCellValue());
        fileInputStream.close();
    }

这里值得注意的是,使用表格对象要注意三种创建方式
POI-HSSF
POI-XSSF
SXSSF
HSSF:Excel97-2003版本,扩展名为.xls。一个sheet最大行数65536,最大列数256。

XSSF:Excel2007版本开始,扩展名为.xlsx。一个sheet最大行数1048576,最大列数16384。

SXSSF:是在XSSF基础上,POI3.8版本开始提供的支持低内存占用的操作方式,扩展名为.xlsx。

Excel版本兼容性是向下兼容。

在读取数据的时候我们需要先判断值类型,才能用对应API

  FileInputStream fileInputStream = new FileInputStream(path + "数据表07.xlsx");
        Workbook workbook=new XSSFWorkbook(fileInputStream);
        Sheet sheet = workbook.getSheetAt(0);
        Row rowTitle = sheet.getRow(0);
        if(rowTitle!=null){
            int cellCount=rowTitle.getPhysicalNumberOfCells();    //拿到第row行的那一行的总个数
            for (int i = 0; i <cellCount ; i++) {  //循环个数取出
                Cell cell = rowTitle.getCell(i);
                if(cell!=null){          //如果不等于空取出值
                    int cellType = cell.getCellType();   //这里是知道我们标题是String,考虑不确定的时候怎么取
                    String cellValue = cell.getStringCellValue();
                    System.out.print(cellValue+"|");
                }
            }
            System.out.println();
        }

下面接着读取对应的数据,这里就需要我们刚刚讲的类型判断

int cellType=cell.getCellType();利用这个,然后判断它的XSSFCell类型再具体输出

//获取表中内容
        int rowCount=sheet.getPhysicalNumberOfRows();
        for(int rowNum=1;rowNum<rowCount;rowNum++){
            Row rowData=sheet.getRow(rowNum); //取出对应的行
            if(rowData!=null){
                int cellCount=rowTitle.getPhysicalNumberOfCells();
                for(int cellNum=0;cellNum<cellCount;cellNum++){
                    System.out.print("["+(rowNum+1+"-"+(cellNum+1)+"]"));
                    Cell cell = rowData.getCell(cellNum);
                    //匹配数据类型
                    if(cell!=null){
                        int cellType=cell.getCellType();
                        switch (cellType){
                            case XSSFCell.CELL_TYPE_STRING: System.out.print("字符串:"+cell.getStringCellValue());break;
                            case XSSFCell.CELL_TYPE_BOOLEAN: System.out.print("布尔:"+cell.getBooleanCellValue());break;
                            case XSSFCell.CELL_TYPE_NUMERIC:
                                if(HSSFDateUtil.isCellDateFormatted(cell)){
                                    System.out.println("日期格式:"+new DateTime(cell.getDateCellValue()).toString("yyyy-MM-dd HH:mm:ss"));break;
                                }else
                                    cell.setCellType(XSSFCell.CELL_TYPE_STRING);
                                System.out.print("整形:"+cell.toString());break;
                            case XSSFCell.CELL_TYPE_BLANK: System.out.print("空");break;
                            case XSSFCell.CELL_TYPE_ERROR: System.out.print("数据类型错误");break;
                            case Cell.CELL_TYPE_FORMULA:
                String formula=cell.getCellFormula();
                System.out.println("公式:"+formula);

                //
                CellValue evaluate = formulaEvaluator.evaluate(cell);
                String cellValue=evaluate.formatAsString();
                System.out.println(cellValue);
                break;
                            default:break;
                        }
                    }
                }
            }
        }


        fileInputStream.close();

如本文“对您有用”,欢迎随意打赏作者,让我们坚持创作!

0 打赏
Enamiĝu al vi
不要为明天忧虑.因为明天自有明天的忧虑.一天的难处一天当就够了。
543文章 68评论 294点赞 593800浏览

随机文章
Java—并发编程(七)JUC集合 – 概览
4年前
SpringMVC笔记10—全局异常处理
5年前
SpringMVC笔记17—拦截器
5年前
RabbitMQ—简单队列模式
5年前
Kotlin-函数进阶—SAM转换(十八)
4年前
博客统计
  • 日志总数:543 篇
  • 评论数目:68 条
  • 建站日期:2020-03-06
  • 运行天数:1927 天
  • 标签总数:23 个
  • 最后更新:2024-12-20
Copyright © 2025 网站备案号: 浙ICP备20017730号 身体没有灵魂是死的,信心没有行为也是死的。
主页
页面
  • 归档
  • 摘要
  • 杂图
  • 问题随笔
博主
Enamiĝu al vi
Enamiĝu al vi 管理员
To be, or not to be
543 文章 68 评论 593800 浏览
测试
测试
看板娘
赞赏作者

请通过微信、支付宝 APP 扫一扫

感谢您对作者的支持!

 支付宝 微信支付