web-dev-qa-db-de.com

Wie erstelle ich eine Excel-Datei (.xlsx) und schreibe in sie?

Es gibt Bibliotheken für Java-Entwickler, die viele Methoden haben, die auf Android nicht funktionieren. 

Ich habe zuerst mit Bibliotheken wie OpenCSV gearbeitet, leider hat Excel bekannte Probleme beim Öffnen von CSV-Dateien.

Dann habe ich versucht zu verwenden:

  • Apache POI - Es gibt definitiv zu viele Methoden. 
  • JExcelAPI - Es funktioniert, aber nur bei alten binären XLS-Dateien.
  • docx4j - wieder zu viele Gläser, weil es auf JAXB basiert, die nicht in Android enthalten ist.

Meine Frage ist, wie kann ich eine einfache Excel-Datei im .xlsx-Format unter Android erstellen, ohne 65k-Methoden zu überschreiten?

16
Nominalista

Erste Antwort: mache es serverseitig.

Wenn dies nicht möglich ist, verwenden Sie einfach JExecelAPI - so ziemlich alles, was xlsx-Dateien liest, auch xls-Dateien.

Jede andere Excel-Bibliothek wird viel zu groß sein.

Ein weiterer Gedanke: Schreiben Sie csv-Dateien entweder manuell oder mit einer der vielen verfügbaren csv-Bibliotheken. Wieder lesen die meisten Anwendungen, die Excel-Dateien lesen, auch CSV-Dateien.

14
GreyBeardedGeek

Da diese Frage eher zu sein scheint: "Wie lassen sich Office Open XML-Dateien für Excel (*.xlsx) am einfachsten erstellen?", Werde ich ein Beispiel geben, das keine Bibliotheken außer den Standardwerten Java.lang, Java.io und Java.util.Zip benötigt.

Eine *.xlsx-Datei ist nichts anderes als ein Zip-Archiv, das XML-Dateien und andere Dateien in einer Verzeichnisstruktur enthält. Wir brauchen also nur eine Möglichkeit, Zip-Archive zu erstellen, zu lesen und zu schreiben und XML-Dateien zu erstellen, zu lesen und zu schreiben. Für den Zip-Teil verwende ich Java.util.Zip und für den XML-Teil verwende ich die String-Manipulation. Das Erstellen und Manipulieren von XML durch Zeichenfolgenmanipulation ist nicht die empfohlene Methode zur Manipulation von XML. Es ist jedoch die einfachste Methode, da keine zusätzlichen XML-Bibliotheken erforderlich sind.

Vollständiges Beispiel:

import Java.io.OutputStream;
import Java.io.ByteArrayOutputStream;

import Java.util.Zip.*;

public class CreateXLSXFromScratch {

 //some static parts of the XLSX file:

 static String content_types_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\"><Default ContentType=\"application/vnd.openxmlformats-package.relationships+xml\" Extension=\"rels\"/><Default ContentType=\"application/xml\" Extension=\"xml\"/><Override ContentType=\"application/vnd.openxmlformats-officedocument.extended-properties+xml\" PartName=\"/docProps/app.xml\"/><Override ContentType=\"application/vnd.openxmlformats-package.core-properties+xml\" PartName=\"/docProps/core.xml\"/><Override ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml\" PartName=\"/xl/sharedStrings.xml\"/><Override ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml\" PartName=\"/xl/styles.xml\"/><Override ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml\" PartName=\"/xl/workbook.xml\"/><Override ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\" PartName=\"/xl/worksheets/sheet1.xml\"/></Types>";

 static String docProps_app_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Properties xmlns=\"http://schemas.openxmlformats.org/officeDocument/2006/extended-properties\"><Application>" + "Created Low level From Scratch" + "</Application></Properties>";

 static String docProps_core_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><cp:coreProperties xmlns:cp=\"http://schemas.openxmlformats.org/package/2006/metadata/core-properties\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:dcterms=\"http://purl.org/dc/terms/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><dcterms:created xsi:type=\"dcterms:W3CDTF\">" + Java.time.Instant.now().truncatedTo(Java.time.temporal.ChronoUnit.SECONDS).toString() + "</dcterms:created><dc:creator>" + "Axel Richter from scratch" + "</dc:creator></cp:coreProperties>";

 static String _rels_rels_xml  = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\"><Relationship Id=\"rId1\" Target=\"xl/workbook.xml\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\"/><Relationship Id=\"rId2\" Target=\"docProps/app.xml\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties\"/><Relationship Id=\"rId3\" Target=\"docProps/core.xml\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties\"/></Relationships>";

 static String xl_rels_workbook_xml_rels_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\"><Relationship Id=\"rId1\" Target=\"sharedStrings.xml\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings\"/><Relationship Id=\"rId2\" Target=\"styles.xml\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\"/><Relationship Id=\"rId3\" Target=\"worksheets/sheet1.xml\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet\"/></Relationships>";

 static String xl_sharedstrings_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><sst count=\"0\" uniqueCount=\"0\" xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\"/>"; 

 static String xl_styles_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\"><numFmts count=\"0\"/><fonts count=\"1\"><font><sz val=\"11.0\"/><color indexed=\"8\"/><name val=\"Calibri\"/><family val=\"2\"/><scheme val=\"minor\"/></font></fonts><fills count=\"2\"><fill><patternFill patternType=\"none\"/></fill><fill><patternFill patternType=\"darkGray\"/></fill></fills><borders count=\"1\"><border><left/><right/><top/><bottom/><diagonal/></border></borders><cellStyleXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\"/></cellStyleXfs><cellXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" xfId=\"0\"/></cellXfs></styleSheet>";

 static String xl_workbook_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><workbook xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"><workbookPr date1904=\"false\"/><bookViews><workbookView activeTab=\"0\"/></bookViews><sheets><sheet name=\"" + "Sheet1" + "\" r:id=\"rId3\" sheetId=\"1\"/></sheets></workbook>";

 static String xl_worksheets_sheet1_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\"><dimension ref=\"A1\"/><sheetViews><sheetView workbookViewId=\"0\" tabSelected=\"true\"/></sheetViews><sheetFormatPr defaultRowHeight=\"15.0\"/><sheetData/><pageMargins bottom=\"0.75\" footer=\"0.3\" header=\"0.3\" left=\"0.7\" right=\"0.7\" top=\"0.75\"/></worksheet>";

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

  // result goes into a ByteArrayOutputStream
  ByteArrayOutputStream resultout = new ByteArrayOutputStream();

  // needed objects
  ZipEntry zipentry = null;
  byte[] data = null;

  // create ZipOutputStream
  ZipOutputStream zipout = new ZipOutputStream(resultout);

  // create the static parts of the XLSX Zip file:

  zipentry = new ZipEntry("[Content_Types].xml");
  zipout.putNextEntry(zipentry);
  data = content_types_xml.getBytes();
  zipout.write(data, 0, data.length);
  zipout.closeEntry();

  zipentry = new ZipEntry("docProps/app.xml");
  zipout.putNextEntry(zipentry);
  data = docProps_app_xml.getBytes();
  zipout.write(data, 0, data.length);
  zipout.closeEntry();

  zipentry = new ZipEntry("docProps/core.xml");
  zipout.putNextEntry(zipentry);
  data = docProps_core_xml.getBytes();
  zipout.write(data, 0, data.length);
  zipout.closeEntry();

  zipentry = new ZipEntry("_rels/.rels");
  zipout.putNextEntry(zipentry);
  data = _rels_rels_xml.getBytes();
  zipout.write(data, 0, data.length);
  zipout.closeEntry();

  zipentry = new ZipEntry("xl/_rels/workbook.xml.rels");
  zipout.putNextEntry(zipentry);
  data = xl_rels_workbook_xml_rels_xml.getBytes();
  zipout.write(data, 0, data.length);
  zipout.closeEntry();

  zipentry = new ZipEntry("xl/sharedStrings.xml");
  zipout.putNextEntry(zipentry);
  data = xl_sharedstrings_xml.getBytes();
  zipout.write(data, 0, data.length);
  zipout.closeEntry();

  zipentry = new ZipEntry("xl/styles.xml");
  zipout.putNextEntry(zipentry);
  data = xl_styles_xml.getBytes();
  zipout.write(data, 0, data.length);
  zipout.closeEntry();

  zipentry = new ZipEntry("xl/workbook.xml");
  zipout.putNextEntry(zipentry);
  data = xl_workbook_xml.getBytes();
  zipout.write(data, 0, data.length);
  zipout.closeEntry();

  // preparing the sheet data:

  Object[][] sheetData = new Object[][] {
   {"Text", "Value", "Formula"},
   {"Text1", 1.23456, "=SIN(B2)"},
   {"Text2", 2.34567, "=SQRT(B3)"},
   {"Text3", 123.456, "=B4/10"}
  };
  String sheetdata = "<sheetData>";
  int r = 0;
  char c = 'A'; --c;
  for (Object[] rowData : sheetData) {
   sheetdata += "<row r=\"" + ++r + "\">";
   c = 'A'; --c;
   for (Object cellData : rowData) {
    sheetdata += "<c r=\"" + Character.toString(++c) + r + "\"";
    if (cellData instanceof String && ((String)cellData).startsWith("=")) {
     sheetdata += "><f>" + ((String)cellData).replace("=", "") + "</f></c>";
    } else if (cellData instanceof String) {
     sheetdata += " t=\"inlineStr\"><is><t>" + ((String)cellData) + "</t></is></c>";
    } else if (cellData instanceof Double) {
     sheetdata += "><v>" + ((Double)cellData) + "</v></c>";
    }
   }
   sheetdata += "</row>";
  }
  sheetdata += "</sheetData>";

  // get the static sheet xml into a buffer for further processing
  StringBuffer xl_worksheets_sheet1_xml_buffer = new StringBuffer(xl_worksheets_sheet1_xml);

  // get position of the <dimension ref=\"A1\"/> in the static xl_worksheets_sheet1_xml
  int dimensionstart = xl_worksheets_sheet1_xml_buffer.indexOf("<dimension ref=\"A1\"/>");
  // replace the <dimension ref=\"A1\"/> with the new dimension
  xl_worksheets_sheet1_xml_buffer = xl_worksheets_sheet1_xml_buffer.replace(
   dimensionstart, 
   dimensionstart + "<dimension ref=\"A1\"/>".length(), 
   "<dimension ref=\"A1:" + Character.toString(c) + r + "\"/>");

  // get position of the <sheetData/> in the static xl_worksheets_sheet1_xml
  int sheetdatastart = xl_worksheets_sheet1_xml_buffer.indexOf("<sheetData/>");
  // replace the <sheetData/> with the prepared sheet date string
  xl_worksheets_sheet1_xml_buffer = xl_worksheets_sheet1_xml_buffer.replace(
   sheetdatastart, 
   sheetdatastart + "<sheetData/>".length(), 
   sheetdata);

  // create the xl/worksheets/sheet1.xml
  zipentry = new ZipEntry("xl/worksheets/sheet1.xml");
  zipout.putNextEntry(zipentry);
  data = xl_worksheets_sheet1_xml_buffer.toString().getBytes();
  zipout.write(data, 0, data.length);
  zipout.closeEntry();

  zipout.finish();

  // now ByteArrayOutputStream resultout contains the XLSX file data

  // writing this data into a file
  try (Java.io.FileOutputStream fileout = new Java.io.FileOutputStream("test.xlsx")) {
   resultout.writeTo(fileout);
   resultout.close();
  }

 }
}
8
Axel Richter

Es ist 2018. Verwenden Sie Microsoft Graph API und erstellen Sie die Excel-Datei in O365.

Microsoft hat einige Beispiele in Angular und C # veröffentlicht. Es ist kein Java, aber es ist ein guter Ausgangspunkt: https://developer.Microsoft.com/en-us/graph/docs/concepts/Excel-write-to-workbook .

Das MS Graph Java SDK ist Android-kompatibel.

Einschränkung - Es gibt keine einfache Möglichkeit, eine Excel-Datei mit der API von Grund auf zu erstellen. Möglicherweise möchten Sie eine leere Arbeitsmappe behalten und jedes Mal klonen.

3
Michal

Verwenden Sie Apache POI und aktivieren Sie Multi Dex, indem Sie einfach compile "com.Android.support:multidex:1.0.1" zu Ihren Abhängigkeiten in build.gradle hinzufügen. Sie müssen auch multiDexEnabled auf true setzen. Damit sollte die Beschränkung der 65k-Methode aufgehoben werden. 

0
Niza Siwale

Wenn Sie die xlsx-Datei nicht aus Quellen lesen müssen, empfehle ich Ihnen, CSV Excel zu verwenden, ist in der Lage, diesen Typ in eine beliebige std-Ausgabe zu konvertieren. 

Selbst wenn Sie Formeln und Zellformatierungen benötigen, gibt es eine Möglichkeit, die von Ihnen zitierte Bibliothek zu verwenden oder Ihren eigenen Xml-Parser zu verwenden, wie von vielen Leuten vor mir gesagt wurde. Das Excel-Format ist nur eine ZIP-Datei mit XML. Diese XML sind hier beschrieben:

https://msdn.Microsoft.com/en-us/library/dd979921(v=office.12).aspx

Wie Sie feststellen werden, ist Excel ein sehr komplexes Format und die einfache Retrokompatibilität hat keine Priorität. Das Erstellen eines eigenen eingeschränkten Parsers mit XPath oder JAXB ist eine schwere Arbeit, aber nicht unmöglich.

Aber ich verstehe nicht, warum Sie die Anzahl der Methoden einschränken wollen. Wenn es darum geht, eingebettete Software zu erstellen, sollten Sie .xlsx meiner Meinung nach nicht verwenden. Dies ist eine zu komplizierte und schwere Datei, um nur Raster zu speichern ...