Apache POI - Excel-Datei einlesen
Aus Byte-Welt Wiki
Version vom 25. Juni 2019, 14:49 Uhr von L-ectron-X (Diskussion | Beiträge)
Mit dem Java-Framework Apache POI kann man recht komfortabel Microsoft Excel-Dateien auslesen und erzeugen (schreiben).
Hier ein vollständiges Beispiel zum Auslesen des Tabelleninhaltes einer beliebigen Excel-Datei. Das heißt, wir mit diesem Code das binäre Format (.xls) sowie das auf XML basierende Format .xslx einlesen.
Diese Klasse wurde mit der Apache License 2.0 veröffentlicht:
Excel-Datei einlesen
1 /*
2 * ExcelFileReader.java
3 *
4 * Copyright (c) 2019 Gernot Segieth - wiki.byte-welt.net
5 *
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use,
10 * copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following
13 * conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 */
27
28 import java.io.File;
29 import java.io.FileNotFoundException;
30 import java.io.FileOutputStream;
31 import java.io.IOException;
32 import java.util.ArrayList;
33 import java.util.Date;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Set;
38 import java.util.logging.Level;
39 import java.util.logging.Logger;
40 import org.apache.poi.EncryptedDocumentException;
41 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
42 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
43 import org.apache.poi.openxml4j.opc.OPCPackage;
44 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
45 import org.apache.poi.ss.usermodel.Cell;
46 import org.apache.poi.ss.usermodel.CreationHelper;
47 import org.apache.poi.ss.usermodel.DateUtil;
48 import org.apache.poi.ss.usermodel.FormulaEvaluator;
49 import org.apache.poi.ss.usermodel.Row;
50 import org.apache.poi.ss.usermodel.Sheet;
51 import org.apache.poi.ss.usermodel.Workbook;
52 import org.apache.poi.ss.util.WorkbookUtil;
53 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
54
55 /**
56 * ExcelFileProxy liest die Excel-Datei ein und erzeugt ein tabellarisches
57 * Abbild der Arbeitsmappe in Form von verschachtelten Listen.
58 *
59 * @author Gernot Segieth
60 */
61 public class ExcelFileProxy {
62
63 private File excelFile;
64 private Workbook workbook;
65 private FormulaEvaluator evaluator;
66 private boolean isEmptyRow;
67
68 /**
69 * Erzeugt einen neuen Excel-Datei-Stellvertreter. ExcelFileProxy liest die
70 * ihm übergebene Excel-Datei ein und erzeugt ein tabellarisches Abbild
71 * davon.
72 *
73 * @param excelFile Die einzulesene Excel-Datei
74 * @throws java.lang.ClassNotFoundException wenn eine Klasse nicht gefunden
75 * wurde
76 * @throws java.io.IOException wenn die Datei nicht eingelesen werde konnte
77 * @throws org.apache.poi.openxml4j.exceptions.InvalidFormatException wenn
78 * es Probleme mit dem Format der Datei oder der Verschlüsselung gibt
79 */
80 public ExcelFileProxy(File excelFile) throws ClassNotFoundException, IOException, InvalidFormatException {
81 this.excelFile = excelFile;
82 createWorkbook(excelFile);
83 }
84
85 /**
86 * Gibt den Inhalt des übergebenen Tabellenblattes in einer geschachtelten
87 * Liste zurück.
88 *
89 * @param sheetIndex der Index des Tabellenblattes
90 * @return eine Liste aus Listen (Zeilen mit Spalten)
91 */
92 public List<List<?>> getSheetContent(int sheetIndex) {
93 evaluator = workbook.getCreationHelper().createFormulaEvaluator();
94 return getSheetContent(sheetIndex, 0, 0, 0, 0);
95 }
96
97 /**
98 * Gibt den Inhalt des übergebenen Tabellenblattes in einer geschachtelten
99 * Liste zurück.
100 *
101 * @param sheetIndex der Index des Tabellenblattes
102 * @param firstRow in dieser Zeile mit dem Auslesen beginnen
103 * @param firstCol in dieser Spalte mit dem Auslesen beginnen
104 * @param lastRow letzte auszulesene Zeile
105 * @param lastCol letzte auszulesene Spalte
106 * @return eine Liste aus Listen (Zeilen mit Spalten)
107 */
108 public List<List<?>> getSheetContent(int sheetIndex, int firstRow, int firstCol, int lastRow, int lastCol) {
109 evaluator = workbook.getCreationHelper().createFormulaEvaluator();
110 Sheet sheet = workbook.getSheetAt(sheetIndex);
111 List<List<?>> sheetData = new ArrayList<>();
112
113 // Range festlegen (bei Übergabe 0 - ermitteln, sonst Range verarbeiten
114 int lastRowNum;
115 if (lastRow < 1) {
116 lastRowNum = sheet.getLastRowNum();
117 } else {
118 lastRowNum = lastRow;
119 }
120
121 for (int actuallyRow = firstRow; actuallyRow <= lastRowNum; actuallyRow++) {
122
123 Row row = sheet.getRow(actuallyRow); //leere Zeile kann NPE auslösen!
124
125 if (row != null) { //leere Zeile abfangen
126 List<Object> rowData = new ArrayList<>();
127 isEmptyRow = true; //Zeile erstmal als leer ansehen
128
129 int lastColNum;
130 if (lastCol < 1) {
131 lastColNum = row.getLastCellNum();
132 } else {
133 lastColNum = lastCol;
134 }
135
136 for (int actuallyCol = firstCol; actuallyCol < lastColNum; actuallyCol++) {
137 Cell cell = row.getCell(actuallyCol);
138 rowData.add(getData(cell));
139 }
140 if (!isEmptyRow) { //leere Zeilen nicht aufnehmen
141 sheetData.add(rowData);
142 }
143 }
144 }
145 return sheetData;
146 }
147
148 /**
149 * Schreibt Daten einer tabellenartig aufgebauten Liste in das Arbeitsblatt.
150 *
151 * @param sheetData die Daten aus der Liste, die in das Tabellenblatt
152 * geschrieben werden sollen
153 * @param sheetName Name des Tabellenblattes
154 */
155 public void setSheetContent(List<List<?>> sheetData, String sheetName) {
156 String safeName = WorkbookUtil.createSafeSheetName(sheetName);
157 CreationHelper createHelper = workbook.getCreationHelper();
158 Sheet sheet = workbook.createSheet(safeName);
159
160 for (int i = 0, j = sheetData.size(); i < j; i++) {
161 Row row = sheet.createRow(i); //Zeile erzeugen
162 List<?> rowList = sheetData.get(i); //Zeile holen
163 for (int x = 0, y = rowList.size(); x < y; x++) {
164 Cell cell = row.createCell(x); //Zelle erzeugen
165
166 Object cellValue = rowList.get(x);
167 if (cellValue instanceof Number) {
168 cell.setCellValue((Double) cellValue);
169 } else if (cellValue instanceof Date) {
170 cell.setCellValue((Date) cellValue);
171 } else if (cellValue instanceof Boolean) {
172 cell.setCellValue((Boolean) cellValue);
173 } else if (cellValue instanceof String) {
174 cell.setCellValue(createHelper.createRichTextString(cellValue.toString()));
175 }
176 }
177 }
178
179 }
180
181 /**
182 * Gibt die Namen aller Tabellenblätter zurück.
183 *
184 * @return die Namen der Tabellenblätter
185 */
186 public String[] getSheetNames() {
187 String[] sheetNames = new String[getNumberOfSheets()];
188 for (int i = 0; i < sheetNames.length; i++) {
189 sheetNames[i] = getSheetName(i);
190 }
191 return sheetNames;
192 }
193
194 /**
195 * Gibt die Anzahl der Tabellenblätter in der Excel-Datei zurück.
196 *
197 * @return die Anzahl
198 */
199 public int getNumberOfSheets() {
200 return workbook.getNumberOfSheets();
201 }
202
203 /**
204 * Gibt den Namen des Tabellenblattes am übergebenen Index zurück.
205 *
206 * @param sheetIndex der Index
207 * @return das Tabelleenblatt
208 */
209 public String getSheetName(int sheetIndex) {
210 return workbook.getSheetName(sheetIndex);
211 }
212
213 /**
214 * Setzt den Namen des Tabellenblattes am übergebenen Index.
215 *
216 * @param index der Index des Tabellenblattes in der Arbeitsmappe
217 * @param sheetName der Name des Tabellenblattes
218 */
219 public void setSheetName(int index, String sheetName) {
220 workbook.setSheetName(index, sheetName);
221 }
222
223 /**
224 * Gibt den Index des aktiven Tabellenblattes zurück.
225 *
226 * @return der Index des aktiven Tabellenblattes
227 */
228 public int getActiveSheetIndex() {
229 return workbook.getActiveSheetIndex();
230 }
231
232 /**
233 * Setzt das aktive Tabellenblatt.
234 *
235 * @param index der Index des aktiven Tabellenblattes in der Arbeitsmappe
236 */
237 public void setActiveSheet(int index) {
238 workbook.setActiveSheet(index);
239 }
240
241 /**
242 * Gibt das Datum der letzten Änderung der Excel-Datei zurück.
243 *
244 * @return
245 */
246 public long lastModified() {
247 return excelFile.lastModified();
248 }
249
250 /**
251 * Gibt den genauen (einzigen) Pfad zur geladenen Excel-Datei zurück.
252 *
253 * @return Der Pfad zur geladenen Excel-Datei. //@throws java.io.IOException
254 */
255 public String getPath() /*throws IOException*/ {
256 return excelFile.getAbsolutePath();
257 }
258
259 /**
260 * Setzt den Pfad zur Excel-Datei und erzeugt ein Abbild des Workbooks (alle
261 * Tabellenblätter).
262 *
263 * @param excelFile
264 * @throws java.lang.ClassNotFoundException
265 * @throws java.io.IOException
266 * @throws org.apache.poi.openxml4j.exceptions.InvalidFormatException
267 */
268 public void setPath(File excelFile) throws ClassNotFoundException, IOException, InvalidFormatException {
269 this.excelFile = excelFile;
270 update();
271 }
272
273 /**
274 * Liest das Workbook der Excel-Datei neu ein.
275 *
276 * @throws java.lang.ClassNotFoundException
277 * @throws java.io.IOException
278 * @throws org.apache.poi.openxml4j.exceptions.InvalidFormatException
279 */
280 public synchronized void update() throws ClassNotFoundException, IOException, InvalidFormatException {
281 createWorkbook(excelFile);
282 }
283
284 public void createWorkbook(Map<String, List<List<?>>> sheetData) throws IOException {
285 Set<String> keys = sheetData.keySet();
286 Iterator<String> it = keys.iterator();
287 while (it.hasNext()) {
288 String key = it.next();
289 this.setSheetContent(sheetData.get(key), key);
290 }
291 createExcelFile(excelFile);
292 }
293
294 //erzeugt ein Workbook aus der übergebenen Excel-Datei
295 private void createWorkbook(File file) throws ClassNotFoundException, IOException, InvalidFormatException {
296 String filename = file.getName().toLowerCase();
297 try {
298 if (filename.endsWith(".xls")) {
299 readHSSFWorkbook(file);
300 //workbook = WorkbookFactory.create(file);
301 } else if (filename.endsWith(".xlsx")) {
302 readXSSFWorkbook(file);
303 } else {
304 throw new IllegalArgumentException("Ausnahmefehler: Die übergebene Datei " + file.getName() + " ist keine valide Microsoft Excel-Datei (*.xls bzw. *.xlsx)!");
305 }
306 } catch (IOException ioe) {
307 Logger.getLogger(ExcelFileProxy.class.getName()).log(Level.SEVERE, null, ioe);
308 throw new IOException("Ausnahmefehler: Die Datei " + file.getName() + " konnte nicht eingelesen werden!");
309 } catch (EncryptedDocumentException ede) {
310 Logger.getLogger(ExcelFileProxy.class.getName()).log(Level.SEVERE, null, ede);
311 throw new EncryptedDocumentException("Ausnahmefehler: Die Datei " + file.getName() + " ist mit einem Passwort geschützt und kann daher nicht geöffnet werden!");
312 } catch (NoClassDefFoundError err) {
313 System.err.println(err.toString());
314 throw new ClassNotFoundException("Schwerer Ausnahmefehler: Klassendefinition nicht gefunden!\nPrüfen Sie die Programmdateien und externen Bibliotheken auf Vollständigkeit!");
315 }
316
317 }
318
319 private void readHSSFWorkbook(File file) throws IOException {
320 POIFSFileSystem fs = new POIFSFileSystem(file);
321 workbook = new HSSFWorkbook(fs.getRoot(), true);
322 fs.close();
323 }
324
325 private void readXSSFWorkbook(File file) throws InvalidFormatException, IOException {
326 OPCPackage pkg = OPCPackage.open(file);
327 workbook = new XSSFWorkbook(pkg);
328 pkg.close();
329 }
330
331 //Schreibt eine Arbeitsmappe in eine Exceldatei
332 private void createExcelFile(File file) throws FileNotFoundException, IOException {
333 try (FileOutputStream fileOut = new FileOutputStream(file)) {
334 workbook.write(fileOut);
335 } catch (FileNotFoundException fnfe) {
336 throw new IOException("Ausnahmefehler: Die Datei " + file.getName() + " konnte nicht erzeugt werden!");
337 } catch (IOException ioe) {
338 throw new IOException("Ausnahmefehler: Die Datei " + file.getName() + " konnte nicht erzeugt werden!");
339 }
340 }
341
342 //Liest die Daten aus einer Zelle und gibt sie zurück.
343 private Object getData(Cell cell) {
344 if (cell != null) {
345
346 switch (cell.getCellType()) {
347 case STRING:
348 String string = cell.getRichStringCellValue().getString();
349 if (string.isEmpty()) {
350 return null;
351 } else {
352 isEmptyRow = false;
353 return string.trim();
354 }
355 case NUMERIC:
356 if (DateUtil.isCellDateFormatted(cell)) {
357 Date date = cell.getDateCellValue();
358 if (date.toString().isEmpty()) {
359 return null;
360 } else {
361 isEmptyRow = false;
362 return date;
363 }
364 } else {
365 Number number = cell.getNumericCellValue();
366 if (number.toString().isEmpty()) {
367 return null;
368 } else {
369 isEmptyRow = false;
370 return number;
371 }
372 }
373
374 case BOOLEAN:
375 Boolean bool = (cell.getBooleanCellValue());
376 if (bool.toString().isEmpty()) {
377 return null;
378 } else {
379 isEmptyRow = false;
380 return bool;
381 }
382
383 case _NONE:
384 case FORMULA:
385 case BLANK:
386 case ERROR:
387 default:
388 return null;
389 }
390 } else {
391 return null;
392 }
393 }
394 }
Beispiel-Code für die Benutzung dieser Klasse
Erläuterungen zum Code
Dieser Beitrag wird derzeit noch bearbeitet. Der Text ist deshalb unvollständig und kann Fehler oder ungeprüfte Aussagen enthalten. |