java - 使用带有 XSSF 和 SAX 的 poi 在 JAVA 中实现内存高效的 XLSX 阅读器,但不知道如何获取公式?
问题描述
我正在尝试.xlsx
在 java 中使用 POI 实现阅读器,因为我主要关心的是内存,所以我使用 XSSF 和 SAX 实现了它这里是我使用事件 API(带有 SAX 的 XSSF)的代码的参考,
但公式是其中之一我想阅读的具有单元格属性的主要内容,例如,我想阅读单元格名称(C12)、单元格值、单元格公式等,但我在公式中苦苦挣扎,不知道如何在不使用工作簿的情况下获取。因为如果我使用工作簿,内存就会出现问题。
有人可以帮我解决问题吗?
解决方案
...您可以获取底层 XML 数据,并自己处理它。这适用于愿意学习一点 .xlsx 文件的低级结构并且乐于在 java 中处理 XML 的中级开发人员。它使用起来相对简单,但需要对文件结构有基本的了解。
因此,首先您需要了解*.xlsx
文件的结构及其各XML
部分的含义。您还需要知道XML
使用解析是如何SAX
工作的。例如 a有ContentHandler
方法startElement
和是什么意思。您还需要知道它们何时被调用以及给定参数的含义。endElement
characters
如果这一切都清楚了,那么你就可以开始编程了。XSSF 和 SAX(事件 API)中的ExampleEventUserModel
示例具有非常基本的功能来理解基础知识。它只从共享字符串表中获取字符串内容,以及与存储在元素中的所有其他内容完全相同。您的链接示例更加简单。它只从共享字符串表中获取字符串内容。v
DZone
我可以提供一个更完整的示例,该示例还可以从元素中获取公式(如果有),并且如果属性指向单元格样式,则f
还使用StylesTable
附加的SharedStringsTable
来获取单元格的。然后,它包含数字格式,还包含字体设置、边框设置……,如果有的话。XSSFCellStyle
s
XSSFCellStyle
例子:
import java.io.InputStream;
import java.util.Iterator;
import org.apache.poi.ooxml.util.SAXHelper;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.BuiltinFormats;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.ParserConfigurationException;
public class ExampleEventUserModel {
public void processAllSheets(String filename) throws Exception {
OPCPackage pkg = OPCPackage.open(filename);
XSSFReader r = new XSSFReader(pkg);
SharedStringsTable sst = r.getSharedStringsTable();
StylesTable st = r.getStylesTable();
XMLReader parser = fetchSheetParser(sst, st);
Iterator<InputStream> sheets = r.getSheetsData();
while(sheets.hasNext()) {
System.out.println("Processing new sheet:\n");
InputStream sheet = sheets.next();
InputSource sheetSource = new InputSource(sheet);
parser.parse(sheetSource);
sheet.close();
System.out.println("");
}
}
public XMLReader fetchSheetParser(SharedStringsTable sst, StylesTable st) throws SAXException, ParserConfigurationException {
XMLReader parser = SAXHelper.newXMLReader();
ContentHandler handler = new SheetHandler(sst, st);
parser.setContentHandler(handler);
return parser;
}
private static class SheetHandler extends DefaultHandler {
private SharedStringsTable sst;
private StylesTable st;
private String lastCharacters; // characters cache to collect character content between startElement and eneElement
private String formula; // stores the formula, if any
private String content; // stores the content, if any
private boolean nextValueIsSSTString; // indicates that next value is from SharedStringsTable
private boolean nextValueIsStyledNumeric; // indicates that next value is a styled numeric value
private XSSFCellStyle cellStyle; // stores the cell style, if any
private DataFormatter formatter; // used to format the styled numeric values
private SheetHandler(SharedStringsTable sst, StylesTable st) {
this.sst = sst;
this.st = st;
this.formatter = new DataFormatter(java.util.Locale.US, true);
}
public void startElement(String uri, String localName, String name,
Attributes attributes) throws SAXException {
// c => start of cell
if(name.equals("c")) {
// print the cell reference
System.out.print(attributes.getValue("r") + " - ");
// get the cell type
String cellType = attributes.getValue("t");
// figure out if the value is an index in the SST
this.nextValueIsSSTString = false;
if(cellType != null && cellType.equals("s")) {
this.nextValueIsSSTString = true;
}
// figure out if the cell has style
this.cellStyle = null;
String styleIdx = attributes.getValue("s");
if (styleIdx != null) {
int styleIndex = Integer.parseInt(styleIdx);
this.cellStyle = st.getStyleAt(styleIndex);
// print that there is cell style for this cell
System.out.print("CellStyle: " + this.cellStyle + " - ");
}
// figure out if the value is an styled numeric value or date
this.nextValueIsStyledNumeric = false;
if(cellType != null && cellType.equals("n") || cellType == null) {
if (this.cellStyle != null) {
this.nextValueIsStyledNumeric = true;
}
}
}
// clear characters cache after each element
this.lastCharacters = "";
}
public void endElement(String uri, String localName, String name)
throws SAXException {
// f => end of formula in a cell
if(name.equals("f")) {
this.formula = lastCharacters;
// print formula
System.out.print("Formula: " + this.formula + " - ");
}
// v => end of value of a cell
if(name.equals("v")) {
this.content = this.lastCharacters;
// process shared string value
if(this.nextValueIsSSTString) {
int idx = Integer.parseInt(lastCharacters);
this.content = sst.getItemAt(idx).getString();
nextValueIsSSTString = false;
}
// process styled numeric value
if(this.nextValueIsStyledNumeric) {
String formatString = cellStyle.getDataFormatString();
int formatIndex = cellStyle.getDataFormat();
if (formatString == null) {
// formatString could not be found, so it must be a builtin format.
formatString = BuiltinFormats.getBuiltinFormat(formatIndex);
}
double value = Double.valueOf(this.content);
this.content = formatter.formatRawCellContents(value, formatIndex, formatString);
nextValueIsStyledNumeric = false;
}
}
// c => end of a cell
if(name.equals("c")) {
// print content
System.out.println("Content: " + this.content);
this.content = "";
}
}
public void characters(char[] ch, int start, int length) {
this.lastCharacters += new String(ch, start, length);
}
}
public static void main(String[] args) throws Exception {
ExampleEventUserModel example = new ExampleEventUserModel();
//example.processAllSheets(args[0]);
example.processAllSheets("ExcelExample.xlsx");
}
}
推荐阅读
- python - (TF-IDF)计算余弦相似度后如何返回五篇相关文章
- javascript - 如何从客户端读取自定义 html 表信息到烧瓶后端
- php - php artisan serve 错误:找不到输入文件(在项目文件夹 Laravel v6 中运行)
- asp.net-core-3.1 - Swashbuckle - Swagger 执行按钮不起作用
- docker - 重新启动 docker 服务会杀死所有容器吗?
- c++ - 谁能告诉我 val[i*c+j] 是如何工作的?
- spring - 在redis中设置会话uuid
- c - 将结构传递给函数不起作用
- debugging - 通过 openocd 和 gdb 调试 stm32f407 时,Rust 调试不会在断点处停止
- oracle - ORA-01436: Toad 中用户数据中的 CONNECT BY 循环由表的 Tab 使用