IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

lire un (très) gros fichier CSV


Sujet :

Langage PHP

  1. #1
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 470
    Points : 5 831
    Points
    5 831
    Billets dans le blog
    1
    Par défaut lire un (très) gros fichier CSV
    Bonsoir,

    je lis des gros fichiers CSV avec fgetcsv. Le problème, c'est que ces fichiers sont trop gros pour être lus d'un coup (je teste sur un fichier de 17 mO). (Si je tente fgetcsv sur le gros fichier, le script s'arrête en plein milieu). J'ai vu qu'une solution est de les découper en petits fichiers : https://gist.github.com/eric-pommere...f20694452ecd5e. J'ai testé le script sur mon gros fichier :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
        $row_count_limit = 60000;
            $file_counter = 1;
            $file_name = 'C:\projets\ticket_rawsrc\csv\testicket\Trends_INC_Données_complètes_data septembre.';
            $file_ext = 'csv';
            $row = 1;
            $ctr = 0;
            $cols = array();
     
            echo "PHP CSV Chunker\n\n";
     
            $f = $file_name .
                $file_ext .
                "\n";
            echo "Ouverture du fichier source -> " .
                $file_name .
                $file_ext .
                "\n";
     
            if (
                ($handle_src = fopen("./$file_name" .
                    ".csv",
                    "r")) !==
                FALSE
            )
            {
     
                $cols = fgetcsv($handle_src,
                    1000,
                    ",");
     
                if (
                    ($handle_dest = fopen("$file_name" .
                        $file_counter .
                        $file_ext,
                        "a+")) !==
                    FALSE
                )
                {
                    fputcsv($handle_dest,
                        $cols);
     
                    while (($data = fgetcsv($handle_src,
                            1000,
                            ",")) !==
                        FALSE)
                    {
                        $num = count($data);
                        fputcsv($handle_dest,
                            $data);
                        $row++;
     
                        if (
                            $row ==
                            $row_count_limit
                        )
                        {
                            fclose($handle_dest);
                            $row = 1;
                            echo "\t Création du fichier  --> " .
                                $file_name .
                                $file_counter .
                                $file_ext .
                                "\n";
                            $handle_dest = fopen("./$file_name" .
                                $file_counter .
                                $file_ext,
                                "a+");
                            $file_counter++;
                            fputcsv($handle_dest,
                                $cols);
     
                        }
                    }
                    fclose($handle_src);
                }
            }
            else
            {
     
            }
     
            echo "Fin du programme \n";
    Mon souci est qu'il s'arrête au 1er fopen (lignes 19 à 24). Pensez-vous que ce script est valable ? Avez-vous une idée pour résoudre mon problème ? Y aurait-il une méthode plus adaptée ?

  2. #2
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 853
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 853
    Points : 44 222
    Points
    44 222
    Par défaut
    Premier problème, tu dois protéger les antislash (C:\\projets\\ticket_rawsrc\\...)
    peut-être pas une obligation

    second problème :

    Mettre ./ en début de nom de fichier signifie que le chemin est relatif au dossier en cours, mais toi tu fourni un chemin absolu.

    En dehors de ça , si tu lis ligne par ligne, je pense que ton script s'arrête car il prend trop de temps. Tu peux changer le temps d’exécution avec la fonction set_time_limit mais tu seras probablement forcé de le faire depuis le php.ini (MAX_EXECUTION_TIME).

  3. #3
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 470
    Points : 5 831
    Points
    5 831
    Billets dans le blog
    1
    Par défaut
    Bonjour,

    t'ayant lu, j'ai pensé, avant de te lire, aussi, qu'il fallait modifier PHP.INI. Sauf que je pensais au paramètre upload_max_filesize . Comme il est déjà à 50 mO, c'est pas ça. Je me suis dit qu'en augmentant max_execution_time , y aurait peut-être pas besoin de découper le fichier. Même en mettant un nombre énorme, ça lit à peine plus (en gros 1800 lignes au lieu de 1500 (sur un total de plus de 8000 lignes)). Donc je suis revenu au découpage. Ayant changé mon adressage relatif du fopen, il ne s'arrête plus là :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
      $row_count_limit = 60000;
            $file_counter = 1;
            $file_name = 'C:\\projets\\ticket_rawsrc\\csv\\testicket\\testdecoupage\\Trends_INC_Données_complètes_data septembre.';
            $file_ext = 'csv';
            $row = 1;
            $ctr = 0;
            $cols = array();
     
            DispMsg::DispMsg("PHP CSV Chunker\n\n",true);
            //echo "PHP CSV Chunker\n\n";
     
     
            DispMsg::dispMsgWithoutMenu("Ouverture du fichier source -> ".$file_name .
                $file_ext .
                "\n",true);
     
     
            if (
                ($handle_src = fopen("$file_name" .
                    "csv",
                    "r")) !==
                FALSE
            )
            {
     
                $cols = fgetcsv($handle_src,
                    1000,
                    ";");
     
                if (
                    ($handle_dest = fopen("$file_name" .
                        $file_counter .".".
                        $file_ext,
                        "a+")) !==
                    FALSE
                )
                {
                    fputcsv($handle_dest,
                        $cols);
     
                    while (($data = fgetcsv($handle_src,
                            4096,
                            ";")) !==
                        FALSE)
                    {
                        $num = count($data);
                        fputcsv($handle_dest,
                            $data);
                        $row++;
     
                        if (
                            $row ==
                            $row_count_limit
                        )
                        {
                            fclose($handle_dest);
                            $row = 1;
                            DispMsg::DispMsg("\t Création du fichier  --> " .
                                $file_name .
                                $file_counter .
                                $file_ext .
                                "\n",true);
                            $handle_dest = fopen("./$file_name" .
                                $file_counter .".".
                                $file_ext,
                                "a+");
                            $file_counter++;
                            fputcsv($handle_dest,
                                $cols);
     
                        }
                    }
                    fclose($handle_src);
                }
            }
            else
            {
     
            }
     
            DispMsg::dispMsgWithoutMenu("Fin du programme \n",true);
    Par contre, il génère un seul fichier (Trends_INC_Données_complètes_data septembre.1.csv), encore plus volumineux que l'original ! Donc il faut trouver autre chose...

    PS : les méthodes statiques DispMsg::dispMsg et DispMsg::dispMsgWithoutMenu, c'est car je suis en orienté objet.

  4. #4
    Expert éminent
    Avatar de Séb.
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    5 269
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2005
    Messages : 5 269
    Points : 8 568
    Points
    8 568
    Billets dans le blog
    17
    Par défaut
    Mon souci est qu'il s'arrête au 1er fopen (lignes 19 à 24).
    C'est donc l'ouverture du fichier qui échoue ? Tu ne dis pas quelle est le message d'erreur

    Tu ne dis pas clairement dans quel contexte tu traites le fichier. Est-ce un script en ligne de commande ou suite à un upload via formulaire ? Dans ce dernier cas le fichier CSV uploadé est-il complet ou tronqué ?

    17 Mo ou 50 Mo c'est rien, PHP devrait le manger en un instant

    PS : dans une chaîne délimitée par des ' le seul caractère à échapper est le ', échapper les \ alourdit la lecture pour rien

  5. #5
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 470
    Points : 5 831
    Points
    5 831
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Séb. Voir le message
    C'est donc l'ouverture du fichier qui échoue ? Tu ne dis pas quelle est le message d'erreur
    Il n'y avait aucun message d'erreur. Simplement, il ne faisait rien. Maintenant que j'ai remplacé les adressages relatifs dans les fopen par des adressages absolus, il ouvre bien le fichier. Par contre, au lieu de le découper, il génère un autre fichier CSV (un seul) un peu plus lourd que l'original...

    Citation Envoyé par Séb. Voir le message
    Tu ne dis pas clairement dans quel contexte tu traites le fichier. Est-ce un script en ligne de commande ou suite à un upload via formulaire ?
    Comme il s'agissait de tester ce script de découpage, j'ai juste mis en dur l'adresse du fichier (ligne 3 du code du post #1)

  6. #6
    Modérateur
    Avatar de grunk
    Homme Profil pro
    Lead dév - Architecte
    Inscrit en
    Août 2003
    Messages
    6 692
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Lead dév - Architecte
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2003
    Messages : 6 692
    Points : 20 244
    Points
    20 244
    Par défaut
    Tant que tu reste dans l'ordre de grandeur des Mo ce ne sont pas des gros fichiers.
    En utilisant fopen et fget_xxx tu lis ligne par ligne donc il n'ya pas de problématique de mémoire (sauf à avoir des ligne des 100 Mo ... )

    La seul contrainte que tu peux rencontrer c'est le temps d'execution qui peut être dépassé. Dans ce cas , deux solution : Soit ta limite est basse et il est acceptable de l'augmenter (un peu), soit les fichiers deviennent vraiment très gros (pls Go) et PHP commence à ne plus être le bon outil pour la tache.

  7. #7
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 470
    Points : 5 831
    Points
    5 831
    Billets dans le blog
    1
    Par défaut
    Nouvel essai ce matin et plus de souci pour ouvrir le fichier (j'avais augmenté max_execution_time dans php.ini) donc pas besoin de le découper en petits fichiers.

  8. #8
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 912
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 912
    Points : 6 705
    Points
    6 705
    Par défaut
    À ta place, je jetterais un œil sur le traitement effectué sur les lignes de ton csv pour voir ce qui prend autant de temps et s'il n'y a pas moyen de le réduire.

  9. #9
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 470
    Points : 5 831
    Points
    5 831
    Billets dans le blog
    1
    Par défaut
    Je ne suis pas très étonné de ce temps, vu que le fichier CSV que je traite comporte 168 colonnes et 9559 lignes (soit 16,5mO)...(je n'ai aucune possibilité de modifier la conception de la base de données d'où est issue ce fichier)

  10. #10
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 912
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 912
    Points : 6 705
    Points
    6 705
    Par défaut
    La question c'est qu'est ce que tu fais avec tes 168 colonnes (et qui prend autant de temps, quand bien même tu aurais à le faire 10.000 fois), car comme dit précédemment la quantité de données n'est pas si énorme que ça.

  11. #11
    Expert éminent
    Avatar de Séb.
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    5 269
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2005
    Messages : 5 269
    Points : 8 568
    Points
    8 568
    Billets dans le blog
    17
    Par défaut
    Je ne suis pas très étonné de ce temps, vu que le fichier CSV que je traite comporte 168 colonnes et 9559 lignes (soit 16,5mO)
    C'est peanuts, le problème est ailleurs.

  12. #12
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 853
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 853
    Points : 44 222
    Points
    44 222
    Par défaut
    La fonction fgetcsv n'est peut-être pas optimum selon les fichiers lui étant fourni. Combien de temps prend le traitement ?

  13. #13
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 470
    Points : 5 831
    Points
    5 831
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par chrtophe Voir le message
    La fonction fgetcsv n'est peut-être pas optimum selon les fichiers lui étant fourni. Combien de temps prend le traitement ?
    Vous allez sourire car ça tourne 2 minutes 30 avant...de tomber sur un bug (que j'espère corriger demain).

  14. #14
    Modérateur
    Avatar de grunk
    Homme Profil pro
    Lead dév - Architecte
    Inscrit en
    Août 2003
    Messages
    6 692
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Lead dév - Architecte
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2003
    Messages : 6 692
    Points : 20 244
    Points
    20 244
    Par défaut
    2min30 pour traiter 16Mo ca me parait énorme. Faudrait avoir les caractéristique de la machine mais à titre d'exemple je retraite des fichiers csv de 100MO (lecture, parsage, récriture des données extraites) en C++ en ~5sec.

  15. #15
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 470
    Points : 5 831
    Points
    5 831
    Billets dans le blog
    1
    Par défaut
    J'ai corrigé 2/3 bugs mais y en a d'autres...

    OK, 2 minutes 30, c'est énorme, mais si au bout du compte, ça génère le résultat attendu, ça m'ira (ça fait quand même 2 ans que je suis dessus !)(bon, il est clair que je suis pas le meilleur)

  16. #16
    Membre expert
    Avatar de cavo789
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mai 2004
    Messages
    1 797
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 797
    Points : 3 076
    Points
    3 076
    Par défaut
    Bonjour

    Si tu en viens à remanier ton code, essaie de faire des "early returns"; vois ci-dessous. Je stoppe net le processus si le fichier n'existerait pas. Ainsi, j'évite un if ... else... et tu réduis donc la complexité, ici et là (deux endroits), ton code.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    if (!($handle_src = fopen("$file_name" . 'csv', 'r'))) {
        throw new \Exception("Oups impossible d'ouvrir le fichier $file_name.csv");
    }
    A++

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [WD24] Comment traiter un très gros fichier CSV
    Par lololebricoleur dans le forum WinDev
    Réponses: 63
    Dernier message: 13/03/2020, 10h30
  2. Lire un très gros fichier chez 1&1
    Par ziteak dans le forum Langage
    Réponses: 0
    Dernier message: 27/06/2011, 19h52
  3. Lire un très gros fichier, quoi utiliser ?
    Par italiasky dans le forum Entrée/Sortie
    Réponses: 4
    Dernier message: 17/09/2008, 23h16
  4. Très gros fichier CSV
    Par kidathom dans le forum Débuter
    Réponses: 6
    Dernier message: 29/04/2008, 14h00
  5. [CSV] Traitement d'un très gros fichier XML ou CSV
    Par Paulux1 dans le forum Langage
    Réponses: 3
    Dernier message: 25/03/2008, 17h05

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo