执行我的 java apache poi 程序后无法打开 Excel 文件,我正在使用文件输出流

Unable to open Excel file after excecuting my java apache poi program and i am using file output stream

我正在使用 Apache poi 将 Mysql 数据提取到 Excel 文件中。代码 运行 正确,但当我尝试打开 excel 文件时显示错误。

package com.telkomsel.excel;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;

import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import com.telkomsel.configuirator.Configurator;
import com.telkomsel.dbconnection.DBConnection;
import com.telkomsel.service.TelkomselEntities;

public class TelkomselExcel {

    DBConnection db = new DBConnection();
    static Configurator configurator = null;
    Connection conn = null;
    static Statement statement = null;
    static ResultSet resultSet = null;

    public static HashMap<Integer, TelkomselEntities> getTelkomselData(Statement statement) {

        configurator = new Configurator();
        String Query = configurator.getProperty("sql_query1");

        HashMap<Integer, TelkomselEntities> all = null;
        TelkomselEntities smsModel = null;

        try {
            all = new HashMap<Integer, TelkomselEntities>();
            resultSet = statement.executeQuery(Query);
            while (resultSet.next()) {

                int hour = resultSet.getInt("hour(timestamp)");
                String count = resultSet.getString("count(1)");

                smsModel = new TelkomselEntities(hour, count, count, count);
                all.put(hour, smsModel);
            }

            smsModel = new TelkomselEntities();

            FileInputStream fis = new FileInputStream(new File("Tracker.xlsx"));

            XSSFWorkbook workbook = new XSSFWorkbook(fis);

            XSSFSheet worksheet = workbook.getSheetAt(0);

            XSSFRow row = null;
            XSSFCell cell;
            int i = 1;

            for (Integer l : all.keySet()) {
                TelkomselEntities us = all.get(l);

                row = worksheet.createRow(i);

                cell = row.createCell(2);
                cell.setCellValue(us.getHour());
                cell = row.createCell(3);
                cell.setCellValue(us.getCharge_Count());

                i++;
            

            }
            fis.close();
            FileOutputStream output_file = new FileOutputStream(new File("Tracker.xlsx"),true);
            
            
            
            System.out.println("SUCCESS");
            
            workbook.write(output_file);
            workbook.close();
            output_file.flush();

            output_file.close();
            

        } catch (Exception e) {

            System.out.println(e);
        }
        return all;

    }

}

我认为文件输出流在将数据转换为字节码时产生了问题。我尝试了一切,但没有用。我的 excel 文件不工作

如您所料,问题隐藏在以下行中:

FileOutputStream output_file = new FileOutputStream(new File("Tracker.xlsx"),true);

从现有 excel(您要更新)创建新的 XSSFWorkbook Java 对象时,XSSFWorkbook 最初是根据您的 excel文件内容,则完全独立于它。证明是XSSFWorkbookJava对象的所有修改根本不会影响原始 excel 文件。 Apache Poi 就是这样工作的!

这就是为什么在编辑完 XSSFWorkbook 后必须将其另存为新的 excel 文件(使用 FileOutputStream)的原因 覆盖 原始文件(从某种意义上说,您现在 更新您的excel 文件并包含所有更改)。

但是正如 the docs 所说,您告诉 FileOutputStream 而不是 用新的和更新的文件覆盖原始 excel 文件但是 将第二个附加到第一个,upsi dupsi!您正在创建一个文件,其中包含原始旧文件的所有字节和新更新文件的所有字节!

要解决问题,只需改用:

FileOutputStream output_file = new FileOutputStream(new File("Tracker.xlsx"),false);

FileOutputStream output_file = new FileOutputStream(new File("Tracker.xlsx"));

大功告成!

编辑:在使用 Apache Poi 之前学习 Apache Poi

看来您使用 FileOutputStream 是错误的,因为您不知道 Apache Poi 的工作原理以及如何使用它。在使用它之前,您可能需要对其进行一些研究,网络上有 完整 的示例和教程! Here they are Apache Poi 自己提供的一些示例,你可能想看看它们。

正如我之前所说,XSSFWorkbook 是用 所有 原始 excel 文件的内容初始化的。因此,如果您从第二行开始填充 XSSFSheet(这就是您实际使用代码所做的事情),您实际上是在要求 XSSFWorkbook 用新数据覆盖现有数据。

您必须改进您的代码,搜索行和单元格中已有的数据,如果您不想,则不要覆盖它。

你的 XSSFWorkbook 中每个 XSSFSheet 的行和单元格使用 0-based 索引编号(这就是你的代码开始填充的原因来自索引 1 的行,正在填充从 第二个 开始的行。

用方法XSSFSheet#getRow(int rownum) you can retreive any row from the current XSSFSheet indicating its 0-based index. If this method returns null, then the row you're asking for has never been used and you have to create it using the method XSSFSheet#createRow(int rownum)。如果没有,那么您要求的行 已经被使用并且在其某些单元格中包含一些数据。

用方法XSSFRow#getCell(int cellnum) you can retrieve any cell from the current XSSFRow indicating its 0-based index. If this method returns null, then the cell you're asking for has never been used and you have to create it using the method XSSFRow#createCell(int cellnum, CellType celltype)。如果没有,那么您要求的单元格 已经被使用并且其中包含一些数据。

您可以使用方法 XSSFCell#getCellType().

检索现有 XSSFCellCellType

您可以使用 XSSFCell#getStringCellValue(), XSSFCell#getNumericCellValue() or XSSFCell#getBooleanCellValue().

等方法检索现有 XSSFCell 的内容(基于其 CellType

其他有用的方法是 XSSFSheet#getLastRowNum() and XSSFRow#getLastCellNum()。第一个 returns 最后 已经 在你的 sheet 中使用的行的索引,第二个 returns 第一个 [=89] 的索引=]没有使用行内的单元格。

这是一个给你的例子(在你的 sheet 最后一个 之后填充 42 行):

public static void main(String[] args) throws EncryptedDocumentException, FileNotFoundException, IOException {
    
        // Step 1: load your excel file as a Workbook
    
        String excelFilePath = "D:\Desktop\textExcel.xlsx";
        XSSFWorkbook workbook = (XSSFWorkbook) WorkbookFactory.create(new FileInputStream(excelFilePath));
        
        // Step 2: modify your Workbook as you prefer
        
        XSSFSheet sheet = workbook.getSheetAt(0);
        int firstUnusedRowIndex = sheet.getLastRowNum() + 1;
        for (int rowIndex = firstUnusedRowIndex ; rowIndex < firstUnusedRowIndex + 42 ; rowIndex++) {
            sheet.createRow(rowIndex).createCell(0, CellType.STRING).setCellValue("New Row n°" + (rowIndex - firstUnusedRowIndex + 1));
        }
        
        // Step 3: update the original excel file
        
        FileOutputStream outputStream = new FileOutputStream(excelFilePath);
        workbook.write(outputStream);
        workbook.close();
        outputStream.close();
}