0
votes

Le code Java ne traite pas un énorme fichier CSV

Je suis nouveau à Java, et je dois écrire un code qui traite un énorme fichiers CSV, plus spécifiquement pour pivoter le fichier et la sortie de manière différente.

Quand je teste le code avec quelques centaines de centaines de Ranges ça marche parfaitement! Mais lorsque je fais le fichier autour de 700k lignes, ce que c'est le cas, il génère un fichier sans aucune valeur!

Voici le schéma de fichier que j'utilise: xxx

et voici le code: xxx

et aussi, existe-t-il un moyen de faire lire / traiter le fichier simultanément ou utiliser des multithreads, je veux dire faire il est plus efficace?

mise à jour:

ici comment la sortie ressemble lorsque je traite le fichier d'origine sortie


10 commentaires

Avez-vous des exceptions?


... et si vous envisagez de manipuler une très grande quantité de données, avez-vous envisagé de convertir le fichier CSV en une base de données?


@ Hovercaffulfeules non je ne reçois aucune exception du tout! et pour le jeu de données, je n'y pensais pas, comme je l'ai mentionné que je suis nouveau à Java


Quelle est la taille du fichier? (en termes de taille de la mémoire)


@jhamon 185 méga octets


Je suis que la question est que vous ne lisez que la langue suivante dans votre tableau de colonnes colonnes = arrayes.aslist (nextline); une seule fois dans la boucle lorsque linenumber == 1


@diarrmuid me semble que vous ne vous êtes pas allé jusqu'à la fin du code, ceci n'est que pour la première ligne de remplir les colonnes que c'est la première rangée.


Ceci est un code assez convolué et inefficace. Vous voulez un tableau de 4 cordes. Et au lieu d'utiliser simplement un tableau et de remplir chaque élément de la matrice, vous remplacez plusieurs fois des parties d'une chaîne, puis divisez la chaîne. Mais de toute façon, vous devez commencer votre programme avec votre débogueur et passer à travers sa ligne de code par ligne, pour voir où le problème est.


De plus, si vous voulez des performances, enveloppez le dex-écrit dans un bufferedWriter. Idem pour le lecteur.


J'inclus également (une partie de) la sortie de la façon dont cela fonctionne, quand cela fonctionne correctement. Ce genre de (ce que j'attends / ce que je vois) différence aide parfois à garder les choses claires.


4 Réponses :


1
votes

Dans ces très grands fichiers, vous obtenez parfois une mauvaise entrée. Le meilleur moment pour vérifier l'entrée de non-sens est dans la lecture, à un niveau d'enregistrement / ligne (pour les fichiers CSV, la ligne est le choix naturel).

Mettez donc une instruction "si" dans la boucle d'itérateur et que vous avez écrasé le programme avec une bonne déclaration d'erreur sur tout ce que vous estimez être une mauvaise entrée. Qui sait, vous pouvez trouver 400 lignes vierges entre un grand nombre de rangées entièrement peuplées. En outre, vous pouvez trouver des caractères de contrôle spéciaux, etc.

Une fois que vous avez l'impression que votre entrée est correcte, vous pouvez commencer à déboguer dans la logique du pivot. Qui sait, vous avez peut-être trouvé un bogue dans la bibliothèque.

Personnellement, je pense que c'est un problème avec les données d'entrée, car vous indiquez que la logique fonctionne bien lorsque vous utilisez des ensembles de données plus petits. Les chances sont quelque chose d'étrange dans le groupe de données plus grand que vous n'avez pas remarqué, en raison de sa taille.


0 commentaires

0
votes

Votre fichier de sortie est plus grand que le fichier d'entrée. Il est possible que lorsque le code est exécuté contre 700K lignes, il produit un énorme fichier difficile pour les éditeurs d'ouvrir.

Quelle est la taille de /users/csv-parser/output.csv lorsque vous l'exécutez pendant 700k lignes?

Avez-vous essayé d'imprimer le contenu de /users/csv-parser/outuput.csv à l'aide du code plutôt que de l'ouvrir à l'aide de l'éditeur?


0 commentaires

-1
votes

Avez-vous essayé de le mettre dans un autre fil / tâche et courez-le? Peut-être qu'il bloque le fil principal ...

Vérifiez ceci: https: //winterbe.com/posts/2015/04/07/java8-concurrency-Tutorial-thread-executor-examples/


0 commentaires

1
votes

Il est vraiment difficile de dire ce qui ne va pas sans une trace de pile complète, car votre code a beaucoup de problèmes potentiels avec performance, utilisation de la mémoire JVM, etc. Je pense qu'il est plus simple de vous donner une solution correcte; À Beats, cela fonctionne avec un fichier texte 700k.

import com.opencsv.CSVReader;
import com.opencsv.CSVWriter;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

public class ReadJSONExample {

    public static void main(String[] args) throws IOException {
        // Move time calculation out of main logic
        long start = System.currentTimeMillis();

        new CsvDataModifier(Paths.get("e:/data.csv"), Paths.get("e:/res.csv")).apply();

        long finish = System.currentTimeMillis();
        System.out.printf("Time elapsed: %d ms", finish - start);
    }
}

final class CsvDataModifier {

    private final Path src;
    private final Path dest;

    public CsvDataModifier(Path src, Path dest) {
        this.src = src;
        this.dest = dest;
    }

    private static final int ROW_NUMBER = 0;
    private static final int COLUMN_NAME = 1;
    private static final int COLUMN_VALUE_STRING = 2;
    private static final int COLUMN_VALUE_FLOAT = 3;
    private static final String[] COLUMN_NAMES = { "row_number", "column_name", "column_value_string", "column_value_float" };

    public void apply() throws IOException {
        // Use `try with recources` to close streams correctly
        try (CSVReader reader = new CSVReader(new FileReader(src.toFile())); 
             CSVWriter writer = new CSVWriter(new FileWriter(dest.toFile()), ',', CSVWriter.NO_QUOTE_CHARACTER)) {
            // key - ordered list of columns in source file
            Map<String, Marker> columnNameFloatMarker = getSourceColumnNamesWithFloatMarker(reader.readNext());
            int posRowNumber = getRowNumberPosition(columnNameFloatMarker.keySet());

            if (columnNameFloatMarker.isEmpty())
                return;

            writer.writeNext(COLUMN_NAMES);

            // Create buffer only once for all lines; do not use string concatenation or replacing
            String[] buf = new String[COLUMN_NAMES.length];

            reader.forEach(values -> {
                buf[ROW_NUMBER] = values[posRowNumber];

                int col = 0;
                // this is just reference to buf[]; if `null` then no output
                String[] resultLine;

                for (Map.Entry<String, Marker> entry : columnNameFloatMarker.entrySet()) {
                    String columnName = entry.getKey();
                    Marker marker = entry.getValue();

                    if ((resultLine = marker.createResultLine(columnName, values[col], buf)) != null)
                        writer.writeNext(resultLine);

                    col++;
                }
            });
        }
    }

    private static final String FLOAT = "_float";
    private static final String STRING = "_string";

    private enum Marker {
        NONE {
            @Override
            public String[] createResultLine(String columnName, String value, String[] buf) {
                return null;
            }
        },
        STRING {
            @Override
            public String[] createResultLine(String columnName, String value, String[] buf) {
                buf[COLUMN_VALUE_STRING] = value;
                buf[COLUMN_VALUE_FLOAT] = " ";
                buf[COLUMN_NAME] = columnName;
                return buf;
            }
        },
        FLOAT {
            @Override
            public String[] createResultLine(String columnName, String value, String[] buf) {
                buf[COLUMN_VALUE_STRING] = " ";
                buf[COLUMN_VALUE_FLOAT] = value;
                buf[COLUMN_NAME] = columnName;
                return buf;
            }
        };

        public abstract String[] createResultLine(String columnName, String value, String[] buf);
    }

    // Source column preprocessing to avoid string comparision; do it only once
    private static Map<String, Marker> getSourceColumnNamesWithFloatMarker(String... columns) {
        if (columns == null || columns.length == 0)
            return Collections.emptyMap();

        Map<String, Marker> map = new LinkedHashMap<>();

        for (int i = 0; i < columns.length; i++) {
            String columnName = columns[i];
            Marker marker = Marker.NONE;

            if (columnName.endsWith(FLOAT)) {
                columnName = columnName.substring(0, columnName.length() - FLOAT.length());
                marker = Marker.FLOAT;
            } else if (columnName.endsWith(STRING)) {
                columnName = columnName.substring(0, columnName.length() - STRING.length());
                marker = Marker.STRING;
            }

            if (map.put(columnName, marker) != null)
                throw new IllegalArgumentException("Column duplication in the source file");
        }

        return map;
    }

    private static int getRowNumberPosition(Set<String> columnNames) {
        int i = 0;

        for (String columnName : columnNames) {
            if ("row_number".equals(columnName))
                return i;
            i++;
        }

        throw new IllegalArgumentException("Source file does not contain 'row_number' column");
    }
}
  • Fichier d'entrée: strong> data.csv ~ 432 MB em> li>
  • Fichier de sortie: strong> res.csv ~ 868 MB em> li>
  • Sorties de console: Strong> Temps écoulé: 21058 MS LI> ul> p>


3 commentaires

Merci beaucoup pour la réponse détaillée! une dernière chose, il génère le vol float / entier entouré de "" (c.-à-d. "0", "Time", "- 1.996583023457193", "") Comment puis-je émettre les chiffres (soit pour la colonne _Float ou Row_Number) sans le double citation? Parce que je dois appuyer sur la sortie à la recherche d'élasticité et je veux garder l'index / la cartographie et les types de données détectables.


@ Basel.ai Stackoverflow.com / Questions / 13969254 / ...


Une dernière chose, comment puis-je émettre le résultat dans un format JSON et non dans un fichier CSV?