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

 C Discussion :

Gros fichiers tronqués par stdin


Sujet :

C

  1. #1
    Expert confirmé
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 104
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 104
    Par défaut Gros fichiers tronqués par stdin
    Bonsoir,
    je m'arrache les cheveux depuis trois jours sur un problème assez bête : quand je lis un fichier sur l'entrée standard, dès qu'il dépasse le millier d'octets, il est tronqué.
    Je voudrais pouvoir utiliser les redirections avec mon programme, par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    mon_programme < gros_fichier.txt
    mais visiblement je ne m'y prends pas de la bonne manière.

    Voici un code simpliste avec lequel je peux reproduire le problème :
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // affiche la taille d'un fichier
    #include<stdio.h>
    #define BUFFER_SIZE 1024
     
    char buffer[BUFFER_SIZE];
    int main() {
       int n;
       unsigned long long int i = 0;
       while (n = fread(buffer, sizeof(char), BUFFER_SIZE, stdin)) {
          i += n;
       }
       printf("%llu\n", i);
     
       return 0;
    }
    Pour les fichiers de moins de 1 Ko, ça m'affiche la bonne taille. Ça marche aussi avec un fichier un peu plus gros que mon buffer, 1197 octets. Mais pour les fichiers plus gros, j'obtiens des valeurs toujours inférieures à 1024.
    J'ai essayé aussi avec fgetc, même résultat. En revanche, pas de problème quand j'ouvre le fichier directement avec fopen, mais alors je ne peux pas utiliser les redirections…

    Si ça peut aider, je suis sous Windows. J'ai essayé sans succès sous cmd et Powershell – mais j'ai l'intuition que ça ne dépend pas du système. C'est agaçant, je suis sûr que je passe à côté d'un truc évident… J'ai besoin de votre aide !
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  2. #2
    Expert confirmé
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Par défaut
    Je vois déjà deux problèmes :

    - La valeur initiale de i doit être égale à 0 et non -1. Avec ton code actuel il manquera toujours au moins 1 octet à la taille affichée. En plus i est censé être non signé ...

    - stdin est toujours ouvert par défaut en mode texte, alors qu'un fichier doit être ouvert en mode binaire pour qu'on puisse obtenir correctement sa taille. En clair, ce code n'a aucune chance de fonctionner.

    A part ça, il faut utiliser %llu pour afficher un long long unsigned int et mettre return 0 si tu veux faire plus joli.

  3. #3
    Expert confirmé
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 104
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 104
    Par défaut
    Ok, je corrige pour la postérité. C'est un code censé reproduire le problème, autant qu'il le fasse correctement '^^

    Pour le -1 je me suis dit, peu importe qu'il soit unsigned ou pas puisque c'est représenté par quelque chose comme FFFFFFFF, et dans tous les cas, si on rajoute 1 ça fait 0.
    Et pourquoi -1 ? Je l'avais mis pour tester fgetc, j'ai juste oublié de le remettre à 0…

    Mais avec tout ça, on parle de la forme et pas du fond
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  4. #4
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Par défaut
    Ce code fonctionne correctement sous linux, donc je pense que Melem est dans le vrai quand il parle de lire en mode binaire.

    Tu pourrais commencer par tester feof() pour voir si effectivement tu es à la fin du fichier, ou si tu es sorti en erreur.

  5. #5
    Expert confirmé
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Par défaut
    Citation Envoyé par Watilin Voir le message
    Mais avec tout ça, on parle de la forme et pas du fond
    On parle bien du fond parce que i doit être initialisé à 0 pour espérer avoir un résultat correct et parce que je te dis qu'il faut ouvrir le fichier en mode binaire donc tu dois utiliser fopen, autrement ça ne marchera jamais.

  6. #6
    Expert confirmé
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 104
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 104
    Par défaut
    Est-ce que ça signifie que le C ne permet pas, sous Windows, de traiter des gros fichiers en utilisant les redirections ?

    Pour situer un peu plus les choses, j'aimerais pouvoir utiliser mon programme dans une chaîne avec le pipe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    prog1 | prog2 | prog3 | etc.
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  7. #7
    Expert confirmé
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Par défaut
    La taille du fichier n'a rien à voir. Le problème c'est que stdin est toujours ouvert par défaut en mode texte, ce qui ne permet pas de calculer correctement la taille d'un fichier (3ème fois que je le répète ). Sous Unix, il n'y a pas de différence entre un fichier texte et binaire mais sous les autres systèmes, cette distinction existe la plupart du temps.

    Pour situer un peu plus les choses, j'aimerais pouvoir utiliser mon programme dans une chaîne avec le pipe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    prog1 | prog2 | prog3 | etc.
    Alors fais get_file_size input.txt | prog2 | prog3 | etc. au lieu de get_file_size < input.txt, comme ça tu pourras utiliser fopen ...

  8. #8
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Par défaut
    Si on va par là, du coup c'est un peu bête de lire le fichier. Autant faire fseek(SEEK_END) + ftell(), ça sera plus rapide.

  9. #9
    Expert confirmé
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 104
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 104
    Par défaut
    Justement, on ne va pas par là. Le code que j'ai donné n'était qu'un exemple

    En fait je veux réaliser un programme de cryptage/décryptage de fichiers, selon un algo perso, et je me heurte à des problèmes d'E/S avant même de commencer…

    Je sais le faire avec fopen. Je sais lire un fichier, écrire dans un autre. Je peux faire mon programme en utilisant uniquement les noms de fichiers passés en argument. Mais ce n'est pas intéressant : les shells mettent à ma disposition les opérateurs <, > et |, pourquoi je ne pourrais pas m'en servir avec mon propre programme ? C'est aussi par curiosité que je pose la question.
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  10. #10
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 610
    Par défaut
    Juste un détail, quelle valeur te renvoie sizeof (char) ? Il y a peu de chances que cette valeur soit incorrecte, mais ce serait un peu bête que les caractères texte soient considérés par défaut comme des wchar sur 16 bits…

  11. #11
    Expert confirmé
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Par défaut
    Citation Envoyé par Watilin
    Mais ce n'est pas intéressant : les shells mettent à ma disposition les opérateurs <, > et |, pourquoi je ne pourrais pas m'en servir avec mon propre programme ? C'est aussi par curiosité que je pose la question.
    Je rêve ! Alors pour la 4ème fois : parce que cela va provoquer l'ouverture du fichier en mode texte. En clair, la commande prog < input.txt va provoquer avant le lancement de la fonction main un code du genre stdin = fopen("input.txt", "r");. Or, si tu veux lire un fichier de manière brute, octet par octet, pour en calculer sa taille par exemple ou pour faire un traitement particulier sur chaque octet dans le fichier, il faut ouvrir le fichier en mode binaire. En conséquence, la seule option qui s'offre à toi est d'ouvrir toi-même le fichier avec fopen ET en mode binaire. Au cas où une lecture t'intéresserait, je te propose celle-ci.

    Citation Envoyé par Obsidian
    Juste un détail, quelle valeur te renvoie sizeof (char)
    sizeof(char) vaut toujours 1, par définition . Tu voulais certainement voir la valeur de CHAR_BIT (défini dans <limits.h>), mais vu qu'on est sur un PC Windows, cette valeur est égale à 8.

  12. #12
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 610
    Par défaut
    Citation Envoyé par Melem Voir le message
    sizeof(char) vaut toujours 1, par définition . Tu voulais certainement voir la valeur de CHAR_BIT (défini dans <limits.h>), mais vu qu'on est sur un PC Windows, cette valeur est égale à 8.
    Mmpf ! Je n'ai plus les yeux en face des trous, moi…
    Merci pour cette correction.

  13. #13
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 410
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 410
    Par défaut
    Un autre problème des flux en mode texte, c'est que les valeurs de caractères correspondant à Ctrl+D (sous *n*x) et Ctrl+Z (sous Windows) signifient la fin du flux...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  14. #14
    Expert confirmé
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 104
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 104
    Par défaut
    Bien. Puisque visiblement je parle une langue que personne ne comprend, il ne me restait plus qu'à chercher la solution par moi-même. Et… J'ai trouvé

    Code C : 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
    #include<stdio.h>
    #include<fcntl.h>
     
    char buffer[1000];
    int n;
     
    int main() {
    	setmode(fileno(stdout), O_BINARY);
    	setmode(fileno(stdin), O_BINARY);
     
    	while (n = fread(buffer, 1, 1000, stdin)) {
    		fwrite(buffer, 1, n, stdout);
    	}
     
    	return 0;
    }

    Problème résolu.
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  15. #15
    Expert confirmé
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Par défaut
    Bien. Puisque visiblement je parle une langue que personne ne comprend, il ne me restait plus qu'à chercher la solution par moi-même.
    On te comprenait parfaitement. Pour ma part, je ne savais tout simplement pas qu'il existait une fonction POSIX qui permettait de modifier le mode d'ouverture d'un fichier sans le réouvrir (comme avec freopen - qui est standard par contre).

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

Discussions similaires

  1. [SP-2007] Upload de gros fichiers par programme
    Par bigboomshakala dans le forum SharePoint
    Réponses: 10
    Dernier message: 31/03/2010, 09h55
  2. buffer "par morceau" pour gros fichiers binaires
    Par Benoit_T dans le forum Langage
    Réponses: 11
    Dernier message: 09/11/2009, 10h58
  3. Solution pour transférer des gros fichiers par HTTP
    Par manu_71 dans le forum Général Conception Web
    Réponses: 3
    Dernier message: 29/07/2009, 12h02
  4. Réponses: 5
    Dernier message: 23/07/2009, 19h49
  5. Upload par FTP avec des gros fichiers
    Par __fabrice dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 8
    Dernier message: 07/06/2006, 12h08

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