微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

我正在使用 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);
                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 文件内容创建的,然后它是完全独立的来自它。证明是XSSFWorkbook Java 对象的所有更改都不会影响原始 Excel 文件。 Apache Poi 就是这样工作的!

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

但正如 the docs 所说,您告诉 FileOutputStream not 用新的和更新的 but 覆盖原始 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 被初始化为 all 原始 excel 文件的内容。因此,如果您从第二行开始填充 XSSFSheet(这就是您实际使用代码所做的),您实际上是在要求您的 XSSFWorkbook 用新数据覆盖现有数据。

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

您的 XSSFSheet 的每个 XSSFWorkbook 的行和单元格都使用基于 0 的 索引进行编号(这就是为什么您的代码从索引 1 开始填充行,正在填充从 第二个 开始的行)。

使用 XSSFSheet#getRow(int rownum) 方法,您可以从当前 XSSFSheet 中检索任何行,指示其 0-based 索引。如果此方法返回 null,则您请求的行从未被使用过,您必须使用方法 XSSFSheet#createRow(int rownum) 创建它。如果没有,那么您要求的行已经被使用,并且在其某些单元格中包含一些数据。

使用 XSSFRow#getCell(int cellnum) 方法,您可以从当前 XSSFRow 中检索任何单元格,指示其 0-based 索引。如果此方法返回 null,则您要求的单元格从未被使用过,您必须使用方法 XSSFRow#createCell(int cellnum,CellType celltype) 创建它。如果没有,那么您要求的单元格已经被使用并且其中包含一些数据。

您可以使用方法 XSSFCell#getCellType() 检索现有 CellTypeXSSFCell

您可以使用XSSFCell#getStringCellValue()XSSFCell#getNumericCellValue()XSSFCell#getBooleanCellValue() 等方法检索现有XSSFCell 的内容(基于其CellType)。

其他有用的方法是 XSSFSheet#getLastRowNum()XSSFRow#getLastCellNum()。第一个返回工作表内最后一个已经使用的行的索引,第二个返回您行内第一个使用的单元格的索引。

这是您的示例(在最后一个现有工作表之后填充工作表的 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();
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。