繁体   English   中英

Apache poi:使用 apache poi 在工作表级别设置自定义属性

[英]Apache poi : setting custom properties at worksheet level using apache poi

public static void main(String[] args) {
  try {
    FileInputStream file = new FileInputStream(new File("D://New Microsoft Excel Worksheet.xlsx"));
    XSSFWorkbook wb = new XSSFWorkbook(file);
    XSSFSheet sheet = wb.createSheet("newsheet5");
    CTWorksheet ctSheet = sheet.getCTWorksheet();

    CTCustomProperties props = ctSheet.addNewCustomProperties();
    props.addNewCustomPr().setId("APACHE POI");
    props.addNewCustomPr().setName("Tender no = 48");
    props.addNewCustomPr().setId("APACHE POI 2");
    props.addNewCustomPr().setName("tender no = 58");
    ctSheet.setCustomProperties(props);

    FileOutputStream out = new FileOutputStream("D://New Microsoft Excel Worksheet.xlsx");
    wb.write(out);
    out.close();
    wb.close();
  } catch (Exception e) {
    e.printStackTrace();
  } 
}

Xlsx 文件在工作表级别写入自定义属性后损坏。

我收到一条错误消息,因为“excel 无法打开文件,因为文件格式或文件扩展名无效。 尝试打开 excel 文件时,验证文件没有损坏并且文件扩展名与文件格式匹配。

工作表自定义属性仅可使用VBA使用。 它们存储在Excel文件中,但值在二进制文档部分customProperty1.bincustomProperty2.bin ,...这不是apache poi提供的访问权限。

使用XSSF需要创建二进制文档部分,然后获取到该二进制文档部分的关系 ID。 然后设置CTCustomProperties - CTCustomProperty 那里的 Id 指向包含值的二进制文档部分,名称是属性名称。

以下完整示例显示了这一点。 它使用当前的apache poi 4.1.2进行测试和工作。 它需要ooxml-schemas-1.4.jar位于 class 路径中,因为默认poi-ooxml-schemas-4.1.2.jar CT* CTclasses 不包含所有需要的低级别。

import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.IOException;
import org.apache.poi.xssf.usermodel.*;

import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;

import org.apache.poi.openxml4j.opc.*;
import org.apache.poi.ooxml.POIXMLDocumentPart;

import java.nio.charset.StandardCharsets;

class CreateExcelSheetCustomProperties {

 static void setSheetCustomProperty(XSSFSheet sheet, String customPropertyName, String customPropertyValue) throws Exception {

  OPCPackage opcpackage = sheet.getWorkbook().getPackage();
  int i = opcpackage.getUnusedPartIndex("/customProperty#.bin");
  PackagePartName partname = PackagingURIHelper.createPartName("/customProperty" + i + ".bin");
  PackagePart part = opcpackage.createPart(partname, "application/vnd.openxmlformats-officedocument.spreadsheetml.customProperty");
  POIXMLDocumentPart customProperty = new POIXMLDocumentPart(part) {
   @Override
   protected void commit() throws IOException {
    PackagePart part = getPackagePart();
    OutputStream out = part.getOutputStream();
    try {
     out.write(customPropertyValue.getBytes(StandardCharsets.UTF_16LE));
     out.close();
    } catch (Exception ex) {
     ex.printStackTrace();
    }; 
   }
  };

  String rId = sheet.addRelation(null, XSSFRelation.CUSTOM_PROPERTIES, customProperty).getRelationship().getId();
  
  CTWorksheet ctSheet = sheet.getCTWorksheet();
  CTCustomProperties props = ctSheet.getCustomProperties();
  if (props == null) props = ctSheet.addNewCustomProperties();
  CTCustomProperty prop = props.addNewCustomPr();
  prop.setId(rId);
  prop.setName(customPropertyName);
 }

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

  try (XSSFWorkbook workbook = new XSSFWorkbook(); 
       FileOutputStream fileout = new FileOutputStream("./Excel.xlsx") ) {

   XSSFSheet sheet = workbook.createSheet();

   setSheetCustomProperty(sheet, "APACHE POI", "Tender no = 48");
   setSheetCustomProperty(sheet, "APACHE POI 2", "tender no = 58");

   workbook.write(fileout);
  }
 }
}

我一直在为同样的问题而苦苦挣扎,并找到了一种使它起作用的方法,但这远非最佳。 无论如何,希望你或其他人能想出一个更好的方法。

package temp.temp;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCustomProperties;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCustomProperty;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;

public class Temp2 {

    public static void main(String[] args) {
        File inputFile = new File("C:\\myspreadsheet.xlsx");
        try (BufferedInputStream fis = new BufferedInputStream(new FileInputStream(inputFile))) {
            XSSFWorkbook wb = new XSSFWorkbook(fis); 
            
            for (int i = 0; i < wb.getNumberOfSheets(); i++) {
                XSSFSheet sheet  = wb.getSheetAt(i);
                System.out.println("\nSheetName=" + sheet.getSheetName());
                
                CTWorksheet ctSheet = sheet.getCTWorksheet();
                CTCustomProperties props = ctSheet.getCustomProperties();
                
                if (props != null) {
                    List<CTCustomProperty> propList = props.getCustomPrList();
                    propList.stream().forEach((prop) -> {
                        POIXMLDocumentPart rel = sheet.getRelationById(prop.getId());
                        if (rel != null) {
                            try (InputStream inp  = rel.getPackagePart().getInputStream()) {
                                byte[] inBytes = inp.readAllBytes();
                                // By experimentation, byte array has two bytes per character with least 
                                //  significant in first byte which is UTF-16LE encoding.  Don't know why!
                                String value = new String(inBytes, "UTF-16LE");
                                System.out.println("   " + prop.getName() + "=" + value);
                            } catch (IOException ioe) {
                                //Error
                            }
                        }
                    }); 
                }
                
            
            }
            wb.close();
        } catch (Exception e) {
            System.out.println(e);
        }
        System.out.println("End");
    }
}

请注意,CTWorksheet 来自 poi-ooxml-schemas-xx.jar 和 CustomProperties 来自 ooxml-schemas-yy.jar,因此两者都必须在类路径中。 如果您正在使用模块(就像我一样),这会带来很大的问题! 祝你好运

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM