使用Apache POI生成和读取excel文件

在项目中经常出现的需求就是,需要将表格形式的数据导出或者将表格形式的数据导入,当然我们可以使用简单的文本格式,使用csv作为后缀,客户也可以使用excel打开,但是那样会出现各种奇怪的问题,比较常见的就是乱码。

在java里面其实已经有了很好的操作库,可以很容易的进行excel文件的操作,那就是Apache POI,本文将延时如何使用poi中的接口,对表格形式数据进行导出和导入。

注:poi还有操作其他文档的库,就不做讨论了。

添加依赖

我们使用maven进行项目的构建管理,在依赖中添加下面的配置即可

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.16</version>
</dependency>

由于excel文件一般有xls后缀和xlsx后缀,这两种文件有较大差异,操作的api是单独的,上面的依赖是操作xlsx所必须的依赖,maven会自动寻找它所以来的poi的组件,如果仅仅是需要操作xls文件,那么可以直接配置

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

本文的项目为了演示两种api的操作,使用的poi-ooxml的组件。

关于项目代码已经上传到了码云,https://git.oschina.net/songxinqiang/BlogExampleCode,可以自行查看

准备

为了演示的需要,我准备了一个模型类,用于表示表格的“一行”,就是一个简单的POJO

public class User implements Serializable {

    private static final long serialVersionUID = 5643553301653588278L;

    private int id;
    private String username;

    public User() {}

    public User(int id, String username) {
        this.id = id;
        this.username = username;
    }

    @Override
    public String toString() {
        return "{id:" + id + ",username:" + username + "}";
    }

    //set、get

}

为了实现导出,我们还需要准备一些数据

List<User> userList = new ArrayList<>();
userList.add(new User(1, "test1"));
userList.add(new User(2, "test2"));
userList.add(new User(3, "test3"));
userList.add(new User(4, "test4"));
userList.add(new User(5, "test5"));
userList.add(new User(6, "test6"));
userList.add(new User(7, "test7"));
userList.add(new User(8, "test8"));

导出表格到文件

将前面的list数据保存到一个文件中,我们需要建立一个excel文件的描述对象,在这个对象中添加数据即可。

如开始时所述,xls和xlsx的文件时不同的,下面分别给出两个方法,首先是操作xls文件的

    /**
     * 将用户列表转换存入xls文件
     *
     * @param userList
     *            用户信息列表
     * @return 保存的临时文件的信息对象,用于后续操作
     */
    public File userListToFile(List<User> userList) {
        HSSFWorkbook workbook = new HSSFWorkbook();
        HSSFSheet spreadsheet = workbook.createSheet("用户列表");

        // 用于第一行的样式,当做标题
        HSSFFont font = workbook.createFont();
        font.setFontHeightInPoints((short) 14);
        font.setItalic(true);
        font.setBold(true);
        HSSFCellStyle style = workbook.createCellStyle();
        style.setFont(font);

        HSSFRow row;
        Cell cell;
        int rowid = 0;
        int cellid = 0;
        row = spreadsheet.createRow(rowid++);
        row.setRowStyle(style);
        row.setHeightInPoints(27);

        cell = row.createCell(cellid);
        cell.setCellValue("编号");
        spreadsheet.setColumnWidth(cellid, 18 * 256);
        cellid++;

        cell = row.createCell(cellid);
        cell.setCellValue("用户名");
        spreadsheet.setColumnWidth(cellid, 18 * 256);
        cellid++;

        for (User user : userList) {
            try {
                cellid = 0;
                row = spreadsheet.createRow(rowid++);

                cell = row.createCell(cellid++);
                cell.setCellValue(user.getId());
                cell = row.createCell(cellid++);
                cell.setCellValue(user.getUsername());
            } catch (Exception e) {
                logger.error("parse list error," + e.getMessage());
            }
        }
        // 文件只是临时文件,在方法返回之后,对文件进行后续的移动位置等操作
        File file = new File("/tmp/userlist.xls");
        try {
            FileOutputStream fos = new FileOutputStream(file);
            workbook.write(fos);
        } catch (Exception e) {
            logger.error("write file failed," + e.getMessage());
        } finally {
            try {
                workbook.close();
            } catch (IOException e1) {
                logger.error("close workbook error," + e1.getMessage());
            }
        }
        return file;
    }

然后是xlsx文件的

    /**
     * 将用户列表转换存入xlsx文件
     *
     * @param userList
     *            用户信息列表
     * @return 保存的临时文件的信息对象,用于后续操作
     */
    public File userListToFile(List<User> userList) {
        XSSFWorkbook workbook = new XSSFWorkbook(XSSFWorkbookType.XLSX);
        XSSFSheet spreadsheet = workbook.createSheet("用户列表");

        // 用于第一行的样式,当做标题
        XSSFFont font = workbook.createFont();
        font.setFontHeightInPoints((short) 14);
        font.setItalic(true);
        font.setBold(true);
        XSSFCellStyle style = workbook.createCellStyle();
        style.setFont(font);

        XSSFRow row;
        Cell cell;
        int rowid = 0;
        int cellid = 0;
        row = spreadsheet.createRow(rowid++);
        row.setRowStyle(style);
        row.setHeightInPoints(27);

        cell = row.createCell(cellid);
        cell.setCellValue("编号");
        spreadsheet.setColumnWidth(cellid, 18 * 256);
        cellid++;

        cell = row.createCell(cellid);
        cell.setCellValue("用户名");
        spreadsheet.setColumnWidth(cellid, 18 * 256);
        cellid++;

        for (User user : userList) {
            try {
                cellid = 0;
                row = spreadsheet.createRow(rowid++);

                cell = row.createCell(cellid++);
                cell.setCellValue(user.getId());
                cell = row.createCell(cellid++);
                cell.setCellValue(user.getUsername());
            } catch (Exception e) {
                logger.error("parse list error," + e.getMessage());
            }
        }
        // 文件只是临时文件,在方法返回之后,对文件进行后续的移动位置等操作
        File file = new File("/tmp/userlist.xlsx");
        try {
            FileOutputStream fos = new FileOutputStream(file);
            workbook.write(fos);
        } catch (Exception e) {
            logger.error("write file failed," + e.getMessage());
        } finally {
            try {
                workbook.close();
            } catch (IOException e1) {
                logger.error("close workbook error," + e1.getMessage());
            }
        }
        return file;
    }

可以看到,他们在操作上大体的方法是一样的,只有少许的差异,具体的代码的意义,还是需要查询javadoc文档的,通过这个方法我们就得到了一个保存有列表中数据的File对象,可以用于后续的处理,在这里我们直接用于文件中数据导入的数据源。

导入表格数据到程序

和导出一样,导入也需要分文件类型进行操作,下面首先是导入xls文件数据的

    /**
     * 读取文件中的值得到记录列表
     *
     * @param file
     *            文件描述信息
     * @return 记录对象列表
     */
    public List<User> fileToList(File file) {
        List<User> userList = new ArrayList<>();
        HSSFWorkbook workbook = null;
        try {
            NPOIFSFileSystem poifs = new NPOIFSFileSystem(file);
            workbook = new HSSFWorkbook(poifs);
        } catch (Exception e) {
            logger.error("read file error:" + e.getMessage());
            return userList;
        }
        HSSFSheet spreadsheet = workbook.getSheetAt(0);
        int rowCount = spreadsheet.getLastRowNum();
        HSSFRow row;
        // 第一行忽略
        for (int rowId = 1; rowId <= rowCount; rowId++) {
            row = spreadsheet.getRow(rowId);

            User user = new User();

            // 这里获取“数字”类型的值得到的是double
            user.setId((int) row.getCell(0).getNumericCellValue());
            user.setUsername(row.getCell(1).getStringCellValue());

            userList.add(user);
        }
        try {
            workbook.close();
        } catch (IOException e) {}

        return userList;
    }

接下来,是xlsx文件的操作

    /**
     * 读取文件中的值得到记录列表
     *
     * @param file
     *            文件描述信息
     * @return 记录对象列表
     */
    public List<User> fileToList(File file) {
        List<User> userList = new ArrayList<>();
        XSSFWorkbook workbook = null;
        try {
            workbook = new XSSFWorkbook(file);
        } catch (Exception e) {
            logger.error("read file error:" + e.getMessage());
            return userList;
        }
        XSSFSheet spreadsheet = workbook.getSheetAt(0);
        int rowCount = spreadsheet.getLastRowNum();
        XSSFRow row;
        // 第一行忽略
        for (int rowId = 1; rowId <= rowCount; rowId++) {
            row = spreadsheet.getRow(rowId);

            User user = new User();

            // 这里获取“数字”类型的值得到的是double
            user.setId((int) row.getCell(0).getNumericCellValue());
            user.setUsername(row.getCell(1).getStringCellValue());

            userList.add(user);
        }
        try {
            workbook.close();
        } catch (IOException e) {}

        return userList;
    }

这里,我们只关心里面的数据,所以导入的时候并没有关心格式那些,代码旧比较简单,有时候可能会关心格式,甚至关心数据的类型那些,具体处理起来就会麻烦一些。

同时,我们同样会发现,其实两种文件的处理代码还是差不多的。

测试

测试的代码比较简单,就是准备数据,调用方法处理,然后观察结果

    public static void main(String[] args) {
        List<User> userList = new ArrayList<>();
        userList.add(new User(1, "test1"));
        userList.add(new User(2, "test2"));
        userList.add(new User(3, "test3"));
        userList.add(new User(4, "test4"));
        userList.add(new User(5, "test5"));
        userList.add(new User(6, "test6"));
        userList.add(new User(7, "test7"));
        userList.add(new User(8, "test8"));

        PoiXlsxService poiXlsx = new PoiXlsxService();
        File xlsx = poiXlsx.userListToFile(userList);
        PoiXlsService poiXls = new PoiXlsService();
        File xls = poiXls.userListToFile(userList);

        userList = poiXlsx.fileToList(xlsx);
        System.out.println(Arrays.toString(userList.toArray()));
        userList = poiXls.fileToList(xls);
        System.out.println(Arrays.toString(userList.toArray()));
    }

小结

文中演示的只是基本简单的操作,基本的数据导出和导入,具体的操作还有很多奇妙的地方,还需要仔细发现。

转载于:https://my.oschina.net/songxinqiang/blog/914789

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值