web-dev-qa-db-fra.com

Lire un fichier csv contenant des millions de lignes via Java le plus rapidement possible

Je souhaite lire des fichiers csv contenant des millions de lignes et utiliser les attributs de mon algorithme décisionnel. Mon code est ci-dessous: 

String csvFile = "myfile.csv";
List<String[]> rowList = new ArrayList();
String line = "";
String cvsSplitBy = ",";
String encoding = "UTF-8";
BufferedReader br2 = null;
try {
    int counterRow = 0;
    br2 =  new BufferedReader(new InputStreamReader(new FileInputStream(csvFile), encoding));
    while ((line = br2.readLine()) != null) { 
        line=line.replaceAll(",,", ",NA,");
        String[] object = line.split(cvsSplitBy);
        rowList.add(object); 
        counterRow++;
    }
    System.out.println("counterRow is: "+counterRow);
    for(int i=1;i<rowList.size();i++){
        try{
           //this method includes many if elses only.
           ImplementDecisionTreeRulesFor2012(rowList.get(i)[0],rowList.get(i)[1],rowList.get(i)[2],rowList.get(i)[3],rowList.get(i)[4],rowList.get(i)[5],rowList.get(i)[6]); 
        }
        catch(Exception ex){
           System.out.printlnt("Exception occurred");   
        }
    }
}
catch(Exception ex){
    System.out.println("fix"+ex);
}

Cela fonctionne bien lorsque la taille du fichier csv n’est pas grande. Cependant, il est vraiment grand. Par conséquent, j'ai besoin d'un autre moyen de lire un csv plus rapidement. Y a-t-il un conseil? Apprécié, merci.

13
Joe Leffrey

Dans cet extrait, je vois deux problèmes qui vous ralentiront considérablement:

while ((line = br2.readLine()) != null) { 
    line=line.replaceAll(",,", ",NA,");
    String[] object = line.split(cvsSplitBy);
    rowList.add(object); 
    counterRow++;
}

Tout d'abord, rowList commence par la capacité par défaut et devra être augmenté plusieurs fois, provoquant toujours une copie de l'ancien tableau sous-jacent vers le nouveau. 

Pire, toutefois, il y a eu une explosion excessive des données dans un objet String []. Vous aurez besoin des colonnes/cellules uniquement lorsque vous appelez ImplementDecisionTreeRulesFor2012 pour cette ligne _ - pas tout le temps lorsque vous lisez ce fichier et que vous traitez toutes les autres lignes. Déplacez la division (ou quelque chose de mieux, comme suggéré par les commentaires) vers la deuxième ligne.

(La création de nombreux objets est mauvaise, même si vous pouvez vous permettre la mémoire.)

Peut-être serait-il préférable d'appeler ImplementDecisionTreeRulesFor2012 pendant que vous lisiez les "millions"? Cela éviterait complètement le tableau rowList et ArrayList.

Plus tard Le report de la scission réduit le temps d'exécution de 10 millions de lignes .__ de 1m8,262s (lorsque le programme n'a plus d'espace disponible) à 13,067.

Si vous n'êtes pas obligé de lire toutes les lignes avant d'appeler Implp ... 2012, le temps est réduit à 4.902.

Enfin écrivez la division et remplacez à la main:

String[] object = new String[7];
//...read...
    String x = line + ",";
    int iPos = 0;
    int iStr = 0; 
    int iNext = -1;
    while( (iNext = x.indexOf( ',', iPos )) != -1 && iStr < 7 ){
        if( iNext == iPos ){
            object[iStr++] = "NA";
        } else {
             object[iStr++] = x.substring( iPos, iNext );
        }
        iPos = iNext + 1;
    }
    // add more "NA" if rows can have less than 7 cells

réduit le temps à 1.983s. C'est environ 30 fois plus rapide que le code d'origine, qui se trouve de toute façon dans OutOfMemory.

9
laune

Utilisez simplement uniVocity-parsers 'analyseur CSV au lieu d'essayer de créer votre analyseur personnalisé. Votre mise en œuvre ne sera probablement pas assez rapide ni suffisamment flexible pour traiter tous les cas critiques.

Il est extrêmement efficace en termes de mémoire et vous pouvez analyser un million de lignes en moins d’une seconde. Ce lien présente une comparaison des performances de nombreuses bibliothèques Java CSV et univocity-parsers vient en tête.

Voici un exemple simple d'utilisation:

CsvParserSettings settings = new CsvParserSettings(); // you'll find many options here, check the tutorial.
CsvParser parser = new CsvParser(settings);

// parses all rows in one go (you should probably use a RowProcessor or iterate row by row if there are many rows)
List<String[]> allRows = parser.parseAll(new File("/path/to/your.csv"));

MAIS, cela charge tout en mémoire. Pour diffuser toutes les lignes, vous pouvez procéder comme suit:

String[] row;
parser.beginParsing(csvFile)
while ((row = parser.parseNext()) != null) {
    //process row here.
}

L’approche la plus rapide consiste à utiliser RowProcessor , ce qui donne également plus de souplesse:

settings.setRowProcessor(myChosenRowProcessor);
CsvParser parser = new CsvParser(settings);
parser.parse(csvFile);

Enfin, il a intégré routines qui utilise l'analyseur pour effectuer certaines tâches courantes (itérer des beans Java, dump ResultSets, etc.).

Cela devrait couvrir les bases, consultez la documentation pour trouver la meilleure approche pour votre cas.

Divulgation: Je suis l'auteur de cette bibliothèque. Il est open-source et gratuit (licence Apache V2.0).

5
Jeronimo Backes

au-dessus de l'univocité susmentionnée, il convient de vérifier 

les 3 d'entre eux seraient comme le temps du commentaire l'analyseur CSV le plus rapide.

La chance est que l'écriture de votre propre analyseur serait plus lente et plus difficile.

1
user3996996

Si vous visez des objets (c'est-à-dire une liaison de données), j'ai écrit une bibliothèque hautes performances sesseltjonna-csv vous pourriez trouver intéressant. Comparaison de benchmark avec SimpleFlatMapper et uniVocity ici .

0
ThomasRS