无法使用 apache POI 在工作簿中创建新的 excel sheet

Cannot create new excel sheet in a workbook using apache POI

我正在尝试将多个文件复制到一个 excel 文件中。 excel 文件中的每个 sheet 将携带一个文件的内容。我需要复制大约 6 个文件。所以生成的文件应该包含 6 sheets。但是当我 运行 我的代码只为单个文件生成 1 sheet 时。我尝试调试它但无法找出原因。

这是我的代码。

 public static void main(String[] args) throws IOException {

    // TODO Auto-generated method stub
    CreateSingleExcelFile cef = new CreateSingleExcelFile();
    cef.fileIterator();
 }

 public void fileIterator() throws IOException{

    File dir = new File("path for files to copy");
    File[] dir_listing = dir.listFiles();
    HSSFWorkbook my_wb = new HSSFWorkbook();                        
    //creating an output stream to copy all files in combined.xls
    BufferedOutputStream bos= new BufferedOutputStream(new FileOutputStream("path of resultant excel sheet"));
    //traversing through a list of files
    for(File file: dir_listing){
        //file: file to be copied.
        add_in_excel(my_wb,bos,file);
        System.out.println("In file :" + file.getName());
    }
    bos.close();
    System.out.println("Files are copied");
}


 private void add_in_excel(HSSFWorkbook copy_wb, BufferedOutputStream bos,File file) throws IOException {
    // TODO Auto-generated method stub
    //creating a new sheet in the copy workbook
    HSSFSheet mySheet =  copy_wb.createSheet(file.getName());

    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
    HSSFWorkbook workbook = new HSSFWorkbook(bis);
    CellStyle cs = copy_wb.createCellStyle();
    cs.setWrapText(true);   

    HSSFSheet sheet = null;
    HSSFRow row = null;
    HSSFCell cell = null;               
    HSSFRow myRow = null;
    HSSFCell myCell = null;
    int sheets = workbook.getNumberOfSheets();          
    int fRow = 3;
    int lRow = 0;
    int count_row=0;

    //traversing through sheets in the 'file'
    for (int iSheet = 0; iSheet < sheets; iSheet++) {                   
        sheet = workbook.getSheetAt(iSheet);                
        if (sheet != null) {                                      
            lRow = sheet.getLastRowNum();
            for (int iRow = fRow; iRow <= lRow; iRow++) {
                row = sheet.getRow(iRow);
                //creating row in the new sheet
                myRow = mySheet.createRow(count_row++);
                if (row != null) {                           
                    for (int iCell = 0; iCell < 4; iCell++) {  
                        //creating a column in the new sheet
                        cell = row.getCell(iCell);
                        myCell = myRow.createCell(iCell);                                
                        myCell.setCellStyle(cs);
                        //setting cell type and adding data in each cell
                        if (cell != null ) {                                
                            myCell.setCellType(cell.getCellType());
                            switch (cell.getCellType()) {
                            case HSSFCell.CELL_TYPE_BLANK:                                      
                               myCell.setCellValue("");
                                break;

                            case HSSFCell.CELL_TYPE_BOOLEAN:
                                myCell.setCellValue(cell.getBooleanCellValue());
                                break;

                            case HSSFCell.CELL_TYPE_ERROR:
                                myCell.setCellErrorValue(cell.getErrorCellValue());
                                break;

                            case HSSFCell.CELL_TYPE_FORMULA:
                                myCell.setCellFormula(cell.getCellFormula());
                                break;

                            case HSSFCell.CELL_TYPE_NUMERIC:
                                if(HSSFDateUtil.isCellDateFormatted(cell))
                                    myCell.setCellValue(cell.getDateCellValue());
                                else
                                    myCell.setCellValue(cell.getNumericCellValue());
                                break;

                            case HSSFCell.CELL_TYPE_STRING:
                                myCell.setCellValue(cell.getStringCellValue());
                                break;
                            default:
                                myCell.setCellFormula(cell.getCellFormula());
                            }                                   
                        }
                    }
                }
            }
        }
    }
    bis.close();           
    copy_wb.write(bos);        
}

由于您没有提到任何异常或堆栈跟踪,我将大胆猜测 - 对于目录中的每个新 excel 文件,您正在做

HSSFWorkbook workbook = new HSSFWorkbook(bis);

在阅读每个 sheet(所有行和单元格)结束时,您继续阅读下一个 sheet,依此类推,直到所有 sheet 都已创建并完成在记忆中。然后你通过

将工作簿本身写到输出流

copy_wb.write(bos);

[我知道这是你知道的事情,但万一将来有人来,这将使他们更容易理解发生了什么,而无需花时间]

我在想你第一次说workbook.write(outputstream)内容写好了。但是您还没有关闭流,并且已经写出了一整本工作簿。下次你想将 另一个工作簿 写入同一个流时,我真的不知道会发生什么。不应该将 sheets 添加到您当前的工作簿(而不是将多个工作簿写入同一输出流)?

我建议创建目标工作簿(如果它不存在)并编写源工作簿的 sheets(不是工作簿本身)。这可能是一个变通办法,但除非我可以将多个工作簿调试到同一个输出流,否则我无法真正建议解决当前问题。

我已将其简化为主要问题:

import org.apache.poi.hssf.usermodel.*;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.BufferedOutputStream;

class CreateSingleExcelFile {

 public static void main(String[] args) throws IOException {
  CreateSingleExcelFile cef = new CreateSingleExcelFile();
  cef.fileIterator();
 }

//This is what you actual doing:
 public void fileIterator() throws IOException{
  HSSFWorkbook my_wb = new HSSFWorkbook();                        
  BufferedOutputStream bos= new BufferedOutputStream(new FileOutputStream("copiedWB.xls"));
  for(int i = 0; i < 3; i++){
   add_in_excel(my_wb, bos,"file" + i);
   System.out.println("In file :" + "file" + i);
  }
  bos.close(); //closing the BufferedOutputStream. The resulting file contains bytes for 3 complete XLS files. 
 }

 private void add_in_excel(HSSFWorkbook copy_wb, BufferedOutputStream bos, String file) throws IOException {
  HSSFSheet mySheet =  copy_wb.createSheet(file);
  copy_wb.write(bos); //write the copy_wb with one new added sheet into the BufferedOutputStream without closing it. But writing a XLS file is complex. So this will not work properly. It will append bytes for a complete XLS workbook onto the stream.
 }
}

您将 copy_wb 和一个新添加的 sheet 写入 BufferedOutputStream 而没有关闭流。但是编写 XLS 文件很复杂。所以这将无法正常工作。它会将完整 XLS 工作簿的字节附加到流中,首先是 1,然后是 2,最后是 3 sheets。但是每次都是一个完整的XLS工作簿文件。

添加所有 sheet 后,关闭 BufferedOutputStream。流和生成的文件包含 3 个完整 XLS 文件的字节。第一个有 1 sheet,第二个有 2 sheets,第三个有 3 sheets。如果使用 Excel 打开,只会读取第一个。

这可行,但不推荐。

//This will work, but is not recommend
 public void fileIterator() throws IOException{
  HSSFWorkbook my_wb = new HSSFWorkbook();                        
  for(int i = 0; i < 3; i++){
   BufferedOutputStream bos= new BufferedOutputStream(new FileOutputStream("copiedWB.xls")); // creating a new BufferedOutputStream for each call of add_in_excel
   add_in_excel(my_wb, bos,"file" + i);
   System.out.println("In file :" + "file" + i);
  }
 }

 private void add_in_excel(HSSFWorkbook copy_wb, BufferedOutputStream bos, String file) throws IOException {
  HSSFSheet mySheet =  copy_wb.createSheet(file);
  copy_wb.write(bos);
  bos.close(); //write the copy_wb with one new added sheet into the BufferedOutputStream and close it.
 }

add_in_excel 的每次调用创建一个新的 BufferedOutputStream。将 copy_wb 和一个新添加的 sheet 写入 BufferedOutputStream 并关闭它。因此,每个 writeclose 都会创建一个新的完整 XLS 文件,其中还有一个 sheet。由于它具有相同的名称,它将覆盖现有文件。

但为什么每次添加新的 sheet 时都要写完整的工作簿?

所以这就是我要做的:

 public void fileIterator() throws IOException{
  HSSFWorkbook my_wb = new HSSFWorkbook();                        
  BufferedOutputStream bos= new BufferedOutputStream(new FileOutputStream("copiedWB.xls")); //create the BufferedOutputStream only for the fileIterator method
  for(int i = 0; i < 3; i++){
   add_in_excel(my_wb, "file" + i);
   System.out.println("In file :" + "file" + i);
  }
  my_wb.write(bos);
  bos.close();  //write into and close the BufferedOutputStream only once after you have added all sheets.
 }

 private void add_in_excel(HSSFWorkbook copy_wb, String file) throws IOException {
  HSSFSheet mySheet =  copy_wb.createSheet(file);
 }

仅为 fileIterator 方法创建 BufferedOutputStream。不要将它传递给 add_in_excel。添加完所有 sheets.

后,仅写入并关闭 BufferedOutputStream 一次