Home » excel » excel – Updating and encrypting existing xlsx file with Apache POI

excel – Updating and encrypting existing xlsx file with Apache POI

Posted by: admin May 14, 2020 Leave a comment

Questions:

I have existing xlsx spreadsheet. I am using Apache POI 3.17 to read it, add some entries and save as password protected spreadsheet in new file.
After I run the program, new file is password protected, but I don’t see new entries, only the ones which existed before. Here is simplified version of the program which opens empty spreadsheet, writes new cell and saves in new file with password. When I open file in Excel 2010 using password I still see empty spreadsheet.
Any help will be appreciated. Thanks

public static void main(String[] args) {

  try {
    POIFSFileSystem fs = new POIFSFileSystem();

    EncryptionInfo info = new EncryptionInfo(EncryptionMode.standard);
    Encryptor enc = info.getEncryptor();
    enc.confirmPassword("passw");


    File is = new File("./empty.xlsx");
    OPCPackage opc = OPCPackage.open(is, PackageAccess.READ_WRITE);

    Workbook wb = WorkbookFactory.create(opc);

    Sheet sheet  = wb.getSheetAt(0);
    Row row = sheet.createRow(1);
    Cell cell = row.createCell(1);
    cell.setCellType(Cell.CELL_TYPE_STRING);
    cell.setCellValue("CRYPT");

    OutputStream encos = enc.getDataStream(fs);
    opc.save(encos);
    opc.close();

    OutputStream fos = new FileOutputStream(new File("./f.xlsx"));
    fs.writeFilesystem(fos);
    fos.close();
  }
  catch (Exception ex) {
    System.out.println(ex.getMessage());
    ex.printStackTrace();
  }
}
How to&Answers:

The problem here is the discrepancy in committing changes between the XSSFWorkbook and it’s OPCPackage. Changes in the XSSFWorkbook will be committed to the OPCPackage only while XSSFWorkbook.write. So if you do not (or cannot) write out the XSSFWorkbook, the OPCPackage stays unchanged.

On other hand, if you write out the XSSFWorkbook, it always commits changes to the OPCPackage from which the workbook was created. So if that was an OPCPackage created from an File, then always this file is updated before the workbook will possibly be written into another file. This is annoying too.

So in my opinion it lacks a possibility for programmmatically influencing the committing process between the XSSFWorkbook and it’s OPCPackage.

But the main problem with your code is that you are writing the OPCPackage, which is not updated, to the Encryptor‘s data stream. Instead you should writing the Workbook, which you have updated.

So for example:

import org.apache.poi.poifs.filesystem.POIFSFileSystem;

import org.apache.poi.poifs.crypt.*;
import org.apache.poi.ss.usermodel.*;

import java.io.*;

class ExcelUpdateAndEncrypt {

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

  POIFSFileSystem fs = new POIFSFileSystem();

  EncryptionInfo info = new EncryptionInfo(EncryptionMode.standard);
  Encryptor enc = info.getEncryptor();
  enc.confirmPassword("passw");

  FileInputStream is = new FileInputStream("./empty.xlsx");
  Workbook wb = WorkbookFactory.create(is);

  Sheet sheet  = wb.getSheetAt(0);
  Row row = sheet.createRow(1);
  Cell cell = row.createCell(1);
  cell.setCellValue("CRYPT");

  OutputStream encos = enc.getDataStream(fs);
  wb.write(encos); 
  wb.close();

  OutputStream os = new FileOutputStream(new File("./f.xlsx"));
  fs.writeFilesystem(os);
  os.close();

 }
}