web-dev-qa-db-fra.com

Streaming POI Apache (SXSSF) pour la lecture

J'ai besoin de lire de gros fichiers Excel et d'importer leurs données dans mon application.

Étant donné que POI prend une grande quantité de tas pour fonctionner, générant souvent des erreurs OutOfMemory, j'ai découvert qu'il existe une API Streaming pour gérer les données Excel de manière série (plutôt que de charger le fichier complètement en mémoire)

J'ai créé un classeur xlsx, avec une seule feuille de calcul, et tapé plusieurs valeurs dans les cellules et trouvé le code suivant pour tenter de le lire:

public static void main(String[] args) throws Throwable {
    // keep 100 rows in memory, exceeding rows will be flushed to disk
    SXSSFWorkbook wb = new SXSSFWorkbook(new XSSFWorkbook(new FileInputStream("C:\\test\\tst.xlsx")));
    SXSSFSheet sheet = (SXSSFSheet) wb.getSheetAt(0);
    Row row = sheet.getRow(0);
    //row is always null
    while(row.iterator().hasNext()){ //-> NullPointerException
        System.out.println(row.getCell(0).getStringCellValue());
    }
}

Cependant, bien qu'il puisse obtenir ses feuilles de calcul correctement, il est toujours accompagné de lignes vides (null).

J'ai recherché et découvert plusieurs exemples de l'API Streaming sur Internet, mais aucun d'entre eux ne concerne lecture les fichiers existants, ils concernent tous la génération de fichiers Excel.

Est-il réellement possible de lire des données à partir de .xlsx fichiers dans un flux?

14
bruno_cw

Après avoir déterré un peu plus, j'ai découvert cela bibliothèque :

Si vous avez utilisé Apache POI dans le passé pour lire des fichiers Excel, vous avez probablement remarqué que sa mémoire n'est pas très efficace. La lecture d'un classeur entier entraînera une forte augmentation de l'utilisation de la mémoire, ce qui peut faire des ravages sur un serveur.

Il existe de nombreuses bonnes raisons pour lesquelles Apache doit lire dans tout le classeur, mais la plupart d'entre elles ont à voir avec le fait que la bibliothèque vous permet de lire et d'écrire avec des adresses aléatoires. Si (et seulement si) vous souhaitez simplement lire le contenu d'un fichier Excel de manière rapide et efficace en mémoire, vous n'avez probablement pas besoin de cette capacité. Malheureusement, la seule chose dans la bibliothèque POI pour lire un classeur de streaming nécessite que votre code utilise un analyseur de type SAX. Toutes les classes conviviales comme Row et Cell sont manquantes dans cette API.

Cette bibliothèque sert de wrapper autour de cette API de streaming tout en préservant la syntaxe de l'API POI standard. Lisez la suite pour voir si cela vous convient.

InputStream is = new FileInputStream(new File("/path/to/workbook.xlsx"));
StreamingReader reader = StreamingReader.builder()
        .rowCacheSize(100)    // number of rows to keep in memory (defaults to 10)
        .bufferSize(4096)     // buffer size to use when reading InputStream to file (defaults to 1024)
        .sheetIndex(0)        // index of sheet to use (defaults to 0)
        .sheetName("sheet1")  // name of sheet to use (overrides sheetIndex)
        .read(is);            // InputStream or File for XLSX file (required)

Il y a aussi SAX Event API , qui lit le document et analyse son contenu à travers des événements.

Si l'empreinte mémoire est un problème, alors pour XSSF, vous pouvez accéder aux données XML sous-jacentes et les traiter vous-même. Ceci est destiné aux développeurs intermédiaires qui souhaitent apprendre un peu la structure de bas niveau des fichiers .xlsx et qui sont heureux de traiter XML en Java. Son relativement simple à utiliser, mais nécessite une compréhension de base de la structure du fichier. L'avantage fourni est que vous pouvez lire un fichier XLSX avec une empreinte mémoire relativement petite.

27
bruno_cw