Verwendung der LightCells API

Eventgesteuerte Architektur

Aspose.Cells bietet die LightCells API, die hauptsächlich darauf ausgelegt ist, Zellendaten einzeln zu manipulieren, ohne ein vollständiges Datenmodell (Verwendung der Zellensammlung usw.) in den Speicher zu laden. Es funktioniert im ereignisgesteuerten Modus.

Um Arbeitsmappen zu speichern, geben Sie den Zellinhalt einzeln an, wenn Sie speichern, und das Komponente speichert ihn direkt in die Ausgabedatei.

Beim Lesen von Vorlagendateien analysiert die Komponente jede Zelle und gibt deren Wert einzeln an.

In beiden Verfahren wird ein Cell-Objekt verarbeitet und dann verworfen, das Workbook-Objekt hält die Sammlung nicht. In diesem Modus wird daher Speicher gespart, wenn Microsoft Excel-Dateien importiert und exportiert werden, die einen großen Datensatz haben, der ansonsten viel Speicher verwenden würde.

Obwohl die LightCells API die Zellen für XLSX- und XLS-Dateien auf dieselbe Weise verarbeitet (sie lädt nicht alle Zellen tatsächlich in den Speicher, sondern verarbeitet eine Zelle und verwirft sie dann), spart sie für XLSX-Dateien effektiver Speicher als für XLS-Dateien aufgrund der unterschiedlichen Datenmodelle und Strukturen der beiden Formate.

Für XLS-Dateien können Entwickler jedoch spezifisch einen temporären Speicherort angeben, um während des Speichervorgangs generierte temporäre Daten zu speichern. Die Verwendung der LightCells API zum Speichern von XLSX-Dateien kann in der Regel etwa 50 % oder mehr Speicher sparen als die herkömmliche Methode, das Speichern von XLS-Dateien kann etwa 20-40 % Speicher sparen.

Schreiben großer Excel-Dateien

Aspose.Cells bietet eine Schnittstelle, LightCellsDataProvider, die in Ihrem Programm implementiert werden muss. Die Schnittstelle stellt den Datenspeicher für das Speichern großer Tabellendateien im leichten Modus dar.

Beim Speichern eines Arbeitsmappen im diesem Modus wird bei jedem Arbeitsblatt in der Arbeitsmappe startSheet(int) überprüft. Für ein Blatt, wenn startSheet(int) true ist, werden alle Daten und Eigenschaften von Zeilen und Zellen dieses Blatts, die gespeichert werden sollen, von dieser Implementierung bereitgestellt. Zuerst wird nextRow() aufgerufen, um den nächsten zu speichernden Zeilenindex zu erhalten. Wenn ein gültiger Zeilenindex zurückgegeben wird (der Zeilenindex muss in aufsteigender Reihenfolge für die zu speichernden Zeilen sein), wird ein Zeilenobjekt, das diese Zeile darstellt, von der Implementierung bereitgestellt, um seine Eigenschaften durch startRow(Row) zu setzen.

Für eine Zeile wird zuerst nextCell() überprüft. Wenn ein gültiger Spaltenindex (der Spaltenindex muss in aufsteigender Reihenfolge für alle Zellen einer Zeile sein) zurückgegeben wird, wird ein Zellenobjekt, das diese Zelle darstellt, bereitgestellt, um die Daten und Eigenschaften durch startCell(Cell) zu setzen. Nachdem die Daten dieser Zelle festgelegt sind, wird diese Zelle direkt in die generierte Tabellendatei gespeichert und die nächste Zelle wird überprüft und verarbeitet.

Das folgende Beispiel zeigt, wie die LightCells API funktioniert.

Das folgende Programm erstellt eine große Datei mit 100.000 Datensätzen in einem Arbeitsblatt, die mit Daten gefüllt sind. Wir haben einige Hyperlinks, Zeichenfolgenwerte, numerische Werte und auch Formeln zu bestimmten Zellen im Arbeitsblatt hinzugefügt. Darüber hinaus haben wir auch einen Bereich von Zellen formatiert.

// For complete examples and data files, please go to https://github.com/aspose-cells/Aspose.Cells-for-Java
public class LightCellsDataProviderDemo implements LightCellsDataProvider {
private final int sheetCount;
private final int maxRowIndex;
private final int maxColIndex;
private int rowIndex;
private int colIndex;
private final Style style1;
private final Style style2;
public LightCellsDataProviderDemo(Workbook wb, int sheetCount, int rowCount, int colCount) {
// set the variables/objects
this.sheetCount = sheetCount;
this.maxRowIndex = rowCount - 1;
this.maxColIndex = colCount - 1;
// add new style object with specific formattings
style1 = wb.createStyle();
Font font = style1.getFont();
font.setName("MS Sans Serif");
font.setSize(10);
font.setBold(true);
font.setItalic(true);
font.setUnderline(FontUnderlineType.SINGLE);
font.setColor(Color.fromArgb(0xffff0000));
style1.setHorizontalAlignment(TextAlignmentType.CENTER);
// create another style
style2 = wb.createStyle();
style2.setCustom("#,##0.00");
font = style2.getFont();
font.setName("Copperplate Gothic Bold");
font.setSize(8);
style2.setPattern(BackgroundType.SOLID);
style2.setForegroundColor(Color.fromArgb(0xff0000ff));
style2.setBorder(BorderType.TOP_BORDER, CellBorderType.THICK, Color.getBlack());
style2.setVerticalAlignment(TextAlignmentType.CENTER);
}
public boolean isGatherString() {
return false;
}
public int nextCell() {
if (colIndex < maxColIndex) {
colIndex++;
return colIndex;
}
return -1;
}
public int nextRow() {
if (rowIndex < maxRowIndex) {
rowIndex++;
colIndex = -1; // reset column index
if (rowIndex % 1000 == 0) {
System.out.println("Row " + rowIndex);
}
return rowIndex;
}
return -1;
}
public void startCell(Cell cell) {
if (rowIndex % 50 == 0 && (colIndex == 0 || colIndex == 3)) {
// do not change the content of hyperlink.
return;
}
if (colIndex < 10) {
cell.putValue("test_" + rowIndex + "_" + colIndex);
cell.setStyle(style1);
} else {
if (colIndex == 19) {
cell.setFormula("=Rand() + test!L1");
} else {
cell.putValue(rowIndex * colIndex);
}
cell.setStyle(style2);
}
}
public void startRow(Row row) {
row.setHeight(25);
}
public boolean startSheet(int sheetIndex) {
if (sheetIndex < sheetCount) {
// reset row/column index
rowIndex = -1;
colIndex = -1;
return true;
}
return false;
}
}
// For complete examples and data files, please go to https://github.com/aspose-cells/Aspose.Cells-for-Java
public class Demo {
private static final String OUTPUT_FILE_PATH = Utils.getDataDir(LightCellsDataProviderDemo.class);
public static void main(String[] args) throws Exception {
// Instantiate a new Workbook
Workbook wb = new Workbook();
// set the sheet count
int sheetCount = 1;
// set the number of rows for the big matrix
int rowCount = 100000;
// specify the worksheet
for (int k = 0; k < sheetCount; k++) {
Worksheet sheet = null;
if (k == 0) {
sheet = wb.getWorksheets().get(k);
sheet.setName("test");
} else {
int sheetIndex = wb.getWorksheets().add();
sheet = wb.getWorksheets().get(sheetIndex);
sheet.setName("test" + sheetIndex);
}
Cells cells = sheet.getCells();
// set the columns width
for (int j = 0; j < 15; j++) {
cells.setColumnWidth(j, 15);
}
// traverse the columns for adding hyperlinks and merging
for (int i = 0; i < rowCount; i++) {
// The first 10 columns
for (int j = 0; j < 10; j++) {
if (j % 3 == 0) {
cells.merge(i, j, 1, 2, false, false);
}
if (i % 50 == 0) {
if (j == 0) {
sheet.getHyperlinks().add(i, j, 1, 1, "test!A1");
} else if (j == 3) {
sheet.getHyperlinks().add(i, j, 1, 1, "http://www.google.com");
}
}
}
// The second 10 columns
for (int j = 10; j < 20; j++) {
if (j == 12) {
cells.merge(i, j, 1, 3, false, false);
}
}
}
}
// Create an object with respect to LightCells data provider
LightCellsDataProviderDemo dataProvider = new LightCellsDataProviderDemo(wb, 1, rowCount, 20);
// Specify the XLSX file's Save options
OoxmlSaveOptions opt = new OoxmlSaveOptions();
// Set the data provider for the file
opt.setLightCellsDataProvider(dataProvider);
// Save the big file
wb.save(OUTPUT_FILE_PATH + "/DemoTest.xlsx", opt);
}
}

Lesen großer Excel-Dateien

Aspose.Cells bietet eine Schnittstelle, LightCellsDataHandler, die in Ihrem Programm implementiert werden muss. Die Schnittstelle stellt den Datenspeicher für das Lesen großer Tabellendateien im leichten Modus dar.

Beim Lesen eines Arbeitsmappen in diesem Modus wird bei jedem Arbeitsblatt in der Arbeitsmappe startSheet() überprüft. Für ein Blatt, wenn startSheet() true zurückgibt, werden alle Daten und Eigenschaften der Zellen in den Zeilen und Spalten des Blatts überprüft und verarbeitet. Für jede Zeile wird startRow() aufgerufen, um zu prüfen, ob sie verarbeitet werden muss. Wenn eine Zeile verarbeitet werden muss, werden zuerst die Eigenschaften der Zeile gelesen und Entwickler können auf ihre Eigenschaften mit processRow() zugreifen.

Wenn auch die Zellen der Zeile verarbeitet werden müssen, gibt processRow() true zurück und startCell() wird für jede vorhandene Zelle in der Zeile aufgerufen, um zu prüfen, ob sie verarbeitet werden muss. Wenn ja, wird processCell() aufgerufen.

Der folgende Beispielcode veranschaulicht diesen Prozess. Das Programm liest eine große Datei mit Millionen von Datensätzen ein. Es dauert etwas Zeit, um jedes Blatt in der Arbeitsmappe zu lesen. Der Beispielcode liest die Datei und ruft die Gesamtzahl der Zellen, Zeichenfolgen und Formeln für jedes Arbeitsblatt ab.

// For complete examples and data files, please go to https://github.com/aspose-cells/Aspose.Cells-for-Java
public class LightCellsTest1 {
public static void main(String[] args) throws Exception {
String dataDir = Utils.getDataDir(LightCellsTest1.class);
LoadOptions opts = new LoadOptions();
LightCellsDataHandlerVisitCells v = new LightCellsDataHandlerVisitCells();
opts.setLightCellsDataHandler((LightCellsDataHandler) v);
Workbook wb = new Workbook(dataDir + "LargeBook1.xlsx", opts);
int sheetCount = wb.getWorksheets().getCount();
System.out.println("Total sheets: " + sheetCount + ", cells: " + v.cellCount + ", strings: " + v.stringCount
+ ", formulas: " + v.formulaCount);
}
}

Eine Klasse, die die LightCellsDataHandler-Schnittstelle implementiert

// For complete examples and data files, please go to https://github.com/aspose-cells/Aspose.Cells-for-Java
public class LightCellsDataHandlerVisitCells implements LightCellsDataHandler {
public int cellCount;
public int formulaCount;
public int stringCount;
public LightCellsDataHandlerVisitCells() {
this.cellCount = 0;
this.formulaCount = 0;
this.stringCount = 0;
}
public int cellCount() {
return cellCount;
}
public int formulaCount() {
return formulaCount;
}
public int stringCount() {
return stringCount;
}
public boolean startSheet(Worksheet sheet) {
System.out.println("Processing sheet[" + sheet.getName() + "]");
return true;
}
public boolean startRow(int rowIndex) {
return true;
}
public boolean processRow(Row row) {
return true;
}
public boolean startCell(int column) {
return true;
}
public boolean processCell(Cell cell) {
this.cellCount = this.cellCount + 1;
if (cell.isFormula()) {
this.formulaCount = this.formulaCount + 1;
} else if (cell.getType() == CellValueType.IS_STRING) {
this.stringCount = this.stringCount + 1;
}
return false;
}
}