【问题标题】:I create Excel file using apache poi. but when i open the excell file it says malformed file need to recover我使用 apache poi 创建 Excel 文件。但是当我打开excel文件时它说格式错误的文件需要恢复
【发布时间】:2017-05-25 06:03:30
【问题描述】:

当我打开文件时,它说文件格式错误,需要恢复。当我按 OK 时,它会打开,我写的数据就在那里。它说**(Excel 完成了文件级验证和修复。此工作簿的某些部分可能已被修复或丢弃。)** 我想纠正这个错误。如何将这个格式错误的 excel 文件转换为格式良好的 excel 文件?

这里是写作部分。

 ArrayList<Schedule> schds = serviceResponce.getSchedules();
                    XSSFWorkbook workbook = new XSSFWorkbook();
                    XSSFSheet sheet = workbook.createSheet("sheet");
                    CellStyle styleHeaders;
DataFormat format = workbook.createDataFormat();
CellStyle styleDataCells;
                    DataFormatter downloadForatter=new DataFormatter();
                    styleDataCells = workbook.createCellStyle();
                    for (Schedule sch : schds) {
                        Row row = sheet.createRow(++rowCount);
                        Cell cellScheduleId = row.createCell(0);
                        Cell cellRouteId = row.createCell(1);
                        Cell cellDepTime = row.createCell(2);
                        Cell cellArrTime = row.createCell(3);
                        Cell cellFromTo = row.createCell(4);
                        Cell cellDay = row.createCell(5);
                        Cell cellStatus = row.createCell(6);

                        downloadForatter.formatCellValue(cellDay);
                        cellScheduleId.setCellValue(Integer.parseInt(sch.getSchedule_id()));
                        styleDataCells.setDataFormat(format.getFormat("0"));
                        cellScheduleId.setCellStyle(styleDataCells);

                        cellRouteId.setCellValue(Integer.parseInt(sch.getRoute_id()));
                        styleDataCells.setDataFormat(format.getFormat("0"));
                        cellRouteId.setCellStyle(styleDataCells);

                        cellDepTime.setCellValue(sch.getDeptature_time());
                        styleDataCells.setDataFormat(format.getFormat("hh:mm"));
                        cellDepTime.setCellStyle(styleDataCells);

                        cellArrTime.setCellValue(sch.getArrival_time());
                        styleDataCells.setDataFormat(format.getFormat("hh:mm"));
                        cellArrTime.setCellStyle(styleDataCells);

                        cellFromTo.setCellValue(sch.getFrom_to());
                        styleDataCells.setDataFormat(format.getFormat("@"));
                        cellFromTo.setCellStyle(styleDataCells);

                        cellDay.setCellValue(sch.getDay());
                        styleDataCells.setDataFormat(format.getFormat("@"));
                        cellDay.setCellStyle(styleDataCells);

                        if (sch.getStatus().equals("Y")) {
                            cellStatus.setCellValue("Active");
                            styleDataCells.setDataFormat(format.getFormat("@"));
                            cellStatus.setCellStyle(styleDataCells);
                        } else {
                            cellStatus.setCellValue("Inactive");
                            styleDataCells.setDataFormat(format.getFormat("@"));
                            cellStatus.setCellStyle(styleDataCells);
                        }
                    }
                    try {
                        String downloadPath = getServletContext().getRealPath("/") + "ExpSchedules.xlsx";
                        File excelFile = new File(downloadPath);
                        if (excelFile != null && excelFile.exists()) {
                            excelFile.delete();
                        }
                        excelFile.createNewFile();
                        FileOutputStream outputStream = new FileOutputStream(downloadPath);
                        workbook.write(outputStream);
                        workbook.close();
                        log.info("path " + downloadPath);

//                        
                        String original_filename = "ExpSchedules.xlsx";
                        ServletContext sc = this.getServletContext();
                        InputStream is = new FileInputStream(excelFile);
                        if (is != null && is.available() > 0) {
                            log.info("IS is not null");
                        } else {
                            log.info("IS is null");
                        }
                        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
                        response.setHeader("Content-Disposition", "attachment; filename=\"" + original_filename + "\"");
//                        
//                        File file = new File(downloadPath);
//                        FileInputStream fileIn = new FileInputStream(file);
                        ServletOutputStream outA = response.getOutputStream();
//
                        byte[] outputByte = new byte[4096];
//
                        while (is.read(outputByte, 0, 4096) != -1) {
                            outA.write(outputByte, 0, 4096);
                        }
                        is.close();
                        outA.flush();
                        outA.close();

【问题讨论】:

  • 你没有关闭输出流。此外,您总是在文件末尾转储整个缓冲区,这意味着您从上一次迭代中转储部分缓冲区 - 基本上您将垃圾附加到文件末尾。考虑使用Files 实用程序类。
  • 我使用的是 poi-3.13 版本。和 microsoft excel 2013
  • @Boris the Spider 请解释一下

标签: java excel apache apache-poi


【解决方案1】:

假设您说的是从Servlet 下载的文件,而不是您在服务器上创建的文件。

问题在于代码的以下部分。

byte[] outputByte = new byte[4096];

while (is.read(outputByte, 0, 4096) != -1) {
    outA.write(outputByte, 0, 4096);
}

您总是试图在响应输出流中写入4096 字节。你的文件内容不会总是4096的倍数,这段代码应该修改如下。

byte[] outputByte = new byte[4096];
int readLen = -1;

while ( (readLen = is.read(outputByte)) != -1) {
    outA.write(outputByte, 0, readLen);
}

除此之外,此代码还有多个问题。检查以下

  1. 您不应该关闭响应输出流,让 Servlet 容器处理它。 Rule is if you didn't open it, don't close it
  2. 您希望一次只有一个用户下载文件,但 Servlet 容器是多线程环境。这意味着多个用户可以同时调用下载 Servlet。然后这段代码将在两个不同的线程中写入同一个文件,这将产生异常或损坏文件。您需要为输出文件创建一个随机名称,或者最好使用File.createTempFile()。刷新到响应输出流后,将其删除。
  3. 最后请将代码模块化,将文件创建代码分离到另一个方法中。

【讨论】:

  • 这确实在第 11 维有效。谢谢你。此应用程序只能由一个管理员用户使用。只有他会下载文件。创建 File.createTempFile() 是最佳实践还是应该保持原样?
  • 你可以使用临时文件的方法,只记得之后清理文件。即使它由单个用户使用,您也不知道用户在文件下载期间是否不会刷新页面。然后同一用户将在服务器上实例化 2 个不同的线程。最佳做法是为不同的请求创建不同的文件。另一个更简单的方法是synchronize servlet 方法,即。 doPost/doGet
  • "另一种更简单的方法是同步 servlet 方法,即 doPost/doGet" - 老实说,该评论值得对整个答案投反对票。
  • @BoristheSpider 我知道,这是蛮力。
猜你喜欢
  • 1970-01-01
  • 2014-06-25
  • 2020-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-23
  • 1970-01-01
相关资源
最近更新 更多