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

r1zk6ea1  于 2021-06-29  发布在  Java
关注(0)|答案(2)|浏览(469)
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文件时,文件扩展名是否与文件的格式匹配。

polhcujo

polhcujo1#

图纸自定义特性只能使用 VBA . 它们存储在 Excel 但值在二进制文档部分中 customProperty1.bin , customProperty2.bin , ... 这没什么什么什么 apache poi 提供到目前为止的访问权限。
使用 XSSF 需要创建二进制文档部分,然后获取该二进制文档部分的关系id。然后设置 CTCustomProperties - CTCustomProperty . 在那里,id指向包含值的二进制文档部分,而名称是属性名。
下面的完整示例显示了这一点。它是测试和工作使用电流 apache poi 4.1.2 . 它需要 ooxml-schemas-1.4.jar 在类路径中,因为默认 poi-ooxml-schemas-4.1.2.jar 不包含所有需要的低电平 CT* -班级。

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);
  }
 }
}
y1aodyip

y1aodyip2#

我一直在努力解决同一个问题,并找到了一种方法,使它工作,但它远远不是最佳的。不管怎么说,这就是它,希望你或其他人能想出一个更好的方法。

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,因此两者都必须位于类路径上。如果您使用的是模块(就像我一样),这会带来很大的问题!祝你好运

相关问题