如何使用POI api在Java中访问受密码保护的Excel工作簿

13

我想读写受密码保护的 Excel 文件。如何使用 Apache POI API 实现此功能。

8个回答

20

POI应该能够打开受保护的xls文件(使用 org.apache.poi.hssf.record.crypt )和受保护的xlsx文件(使用 org.apache.poi.poifs.crypt )。你试过了吗?

如果你正在使用HSSF(针对xls文件),你需要在打开文件之前设置密码。你可以通过调用以下方法来实现:

 org.apache.poi.hssf.record.crypto.Biff8EncryptionKey.setCurrentUserPassword(password);

接下来,HSSF应该能够打开您的文件。

对于XSSF,您需要类似以下内容:

POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream("protect.xlsx"));
EncryptionInfo info = new EncryptionInfo(fs);
Decryptor d = new Decryptor(info);
d.verifyPassword(Decryptor.DEFAULT_PASSWORD);
XSSFWorkbook wb = new XSSFWorkbook(d.getDataStream(fs));

或者,在较新版本的Apache POI中,WorkbookFactory支持在打开时提供密码,所以您可以采取类似以下方式的操作:

Workbook wb = WorkbookFactory.create(new File("protected.xls"), "password");

这将适用于HSSF和XSSF,根据格式选择正确的工具,并以适当的方式传递给定的密码。


在使用NPOI时,有没有办法检查文件是否受到密码保护? - Sandeep Kumar
1
对于XSSF,它会产生这个异常org.apache.poi.EncryptedDocumentException: Export Restrictions in place - please install JCE Unlimited Strength Jurisdiction Policy files - KKK
@ɢʜʘʂʈʀɛɔʘɴ,您需要安装适当的JVM加密,目前您正在使用损坏/削弱的低强度加密,无法处理任何现代内容。 - Gagravarr

2
官方文档提供了有关 xls、xlsx 和其他支持格式的加密和解密详细说明,链接如下:http://poi.apache.org/encryption.html
例如,在二进制格式(xls)中:
// XOR/RC4 decryption for xls
Biff8EncryptionKey.setCurrentUserPassword("pass");
NPOIFSFileSystem fs = new NPOIFSFileSystem(new File("file.xls"), true);
HSSFWorkbook hwb = new HSSFWorkbook(fs.getRoot(), true);
Biff8EncryptionKey.setCurrentUserPassword(null);

对于基于XML的格式(xlsx):

EncryptionInfo info = new EncryptionInfo(filesystem);
Decryptor d = Decryptor.getInstance(info);

try {
    if (!d.verifyPassword(password)) {
        throw new RuntimeException("Unable to process: document is encrypted");
    }

    InputStream dataStream = d.getDataStream(filesystem);

    // parse dataStream

} catch (GeneralSecurityException ex) {
    throw new RuntimeException("Unable to process encrypted document", ex);
}

2

代码:

FileInputStream fileInput = new FileInputStream("2.xls");         
BufferedInputStream bufferInput = new BufferedInputStream(fileInput);            
POIFSFileSystem poiFileSystem = new POIFSFileSystem(bufferInput);            
Biff8EncryptionKey.setCurrentUserPassword("test"); 
HSSFWorkbook workbook = new HSSFWorkbook(poiFileSystem, true); 

使用的jar包:

  • commons-codec-1.5.jar
  • commons-logging-1.1.jar
  • dom4j-1.6.jar
  • jsr173_1.0_api.jar
  • junit-4.11.jar
  • log4j-1.2.13.jar
  • poi-3.10-FINAL-20140208.jar
  • poi-excelant-3.10-FINAL-20140208.jar
  • poi-ooxml-3.10-FINAL-20140208.jar
  • poi-ooxml-schemas-3.10-FINAL-20140208.jar
  • resolver.jar
  • xbean.jar
  • xbean_xpath.jar
  • xmlbeans-qname.jar
  • xmlpublic.jar

2
如果整个工作簿已经被密码保护(通过Excel菜单文件 > 另存为... > 工具 > 常规选项...然后提供密码),那么该文件将被加密,您无法通过POI读取或写入工作簿。

Excel另存为常规选项


1

Apache POI是用于Excel处理的好API。 但是POI API仅提供读取受密码保护的Excel文件的选项。 没有写入带密码的Excel文件的选项。

使用Apache POI创建受密码保护的Excel文件?

查看此线程以了解有关受密码保护的Excel的更多信息。


1

对于 xlsx 文件,我尝试了各种解决方案都不起作用。经过多次尝试和错误,我找到了一个可行的方法。

以下是我的工作解决方案,使用 poi-4.0.1.jar 和 poi-ooxml-4.0.1.jar。

private OutputStream getEncryptingOutputStream(POIFSFileSystem fileSystem, String password) throws IOException, GeneralSecurityException
{
    EncryptionInfo encryptionInfo = new EncryptionInfo(EncryptionMode.standard);
    Encryptor encryptor = encryptionInfo.getEncryptor();
    encryptor.confirmPassword(password);
    return encryptor.getDataStream(fileSystem);
}

private void encryptSpreadSheet(String sourcePath, String destinationPath) throws IOException, GeneralSecurityException, InvalidFormatException
{
    try (POIFSFileSystem fileSystem = new POIFSFileSystem())
    {
      //sourcePath = "/var/tmp/dummy.xlsx"
      //destinationPath = "/var/tmp/dummy_encrypted.xlsx"
      try (Workbook wb = WorkbookFactory.create(new File(sourcePath));
            OutputStream out = getEncryptingOutputStream(fileSystem, "password");)
      {
         wb.write(out);
      }

      try (FileOutputStream fileOutputStream = new FileOutputStream(new File(destinationPath)))
      {
          fileSystem.writeFilesystem(fileOutputStream);
      }
    }
}

0
请使用以下代码使用Apache POI保存Excel文件并设置密码保护。
FileOutputStream outputStream = null;
XSSFWorkbook workbook = new XSSFWorkbook();

try {
    outputStream = new FileOutputStream("Test.xlsx");

    XSSFSheet shtSummary = workbook.createSheet("Test");


    workbook.write(outputStream);
  } catch (Exception ex) {
        ex.printStackTrace();
  } finally {
        outputStream.close();
  }

  POIFSFileSystem fs = new POIFSFileSystem();
  EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
  Encryptor enc = info.getEncryptor();
  enc.confirmPassword("mypassword");

  OPCPackage opc = OPCPackage.open(new File("Test.xlsx"), PackageAccess.READ_WRITE);
  OutputStream os = enc.getDataStream(fs);
  opc.save(os);
  opc.close();

  FileOutputStream fos = new FileOutputStream("Test.xlsx");
  fs.writeFilesystem(fos);
  fos.close();

这段代码运行良好。此解决方案适用于 .xslx 格式。

以下代码适用于 .xls 格式。

String fname = "Test.xls";

FileInputStream fileInput = null;
BufferedInputStream bufferInput = null;
POIFSFileSystem poiFileSystem = null;
FileOutputStream fileOut = null;

try {
    fileInput = new FileInputStream(fname);
    bufferInput = new BufferedInputStream(fileInput);
    poiFileSystem = new POIFSFileSystem(bufferInput);

    Biff8EncryptionKey.setCurrentUserPassword("mypassword");
    HSSFWorkbook workbook = new HSSFWorkbook(poiFileSystem, true);
    HSSFSheet sheet = workbook.getSheetAt(0);

    HSSFRow row = sheet.createRow(0);
    Cell cell = row.createCell(0);

    cell.setCellValue("THIS WORKS!");

    fileOut = new FileOutputStream(fname);
    workbook.writeProtectWorkbook(Biff8EncryptionKey.getCurrentUserPassword(), "");
    workbook.write(fileOut);
}
catch (Exception ex) {

    System.out.println(ex.getMessage());
}
finally {
    try {

        bufferInput.close();
    }
    catch (IOException ex) {

        System.out.println(ex.getMessage());
    }

    try {

        fileOut.close();
    }
    catch (IOException ex) {

        System.out.println(ex.getMessage());
    }
}

这两个解决方案都对我有用。这是我发现可行的好方法。


0
try 
{
    InputStream is = new FileInputStream("myfile.xlsx"); 
    POIFSFileSystem pfs = new POIFSFileSystem(is);

    EncryptionInfo info = new EncryptionInfo(pfs);
    Decryptor d = Decryptor.getInstance(info);

    if (!d.verifyPassword("passwordForFile")) 
    {
        System.out.println("Incorrect password!");
    }
    else 
    {
        System.out.println("Correct password!");

        //InputStream dataStream = d.getDataStream(pfs);

        // parse dataStream
    }
}
catch (Exception ex) 
{
    throw new RuntimeException("Unable to process encrypted document", ex);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接