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++Builder Discussion :

TFileStream et valeur retournée


Sujet :

C++Builder

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Profil pro
    lkjlgj
    Inscrit en
    Février 2007
    Messages
    255
    Détails du profil
    Informations personnelles :
    Localisation : Angola

    Informations professionnelles :
    Activité : lkjlgj

    Informations forums :
    Inscription : Février 2007
    Messages : 255
    Par défaut TFileStream et valeur retournée
    Bonjour à tous !

    J'essaie de lire un gros fichier par blocs.
    N'ayant pas compris le FileMapping, j'essaie plutôt avec des classes trouvées dans C++Builder : TFileStream et TMemoryStream.

    J'ai un doute quant au fonctionnement de la méthode CopyFrom qui devrait me permettre
    de copier des blocs (60000 bytes dans l'exemple ci-bas). En effet, dès que le dernier bloc est lu et copié vers un TMemoryStream - parceque celui-ci ne mesure pas 60000 bytes - ça provoque un "Stream Read Error" que je ne peux même pas contourner avec un try / catch ?!?!?

    Si vous avez des suggestions...

    Voir le code source suivant :

    Code : 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
     
    TBytes myBytes;
     
    std::auto_ptr<TFileStream> LFileStream(new TFileStream(fileName.c_str(), fmOpenRead));
    std::auto_ptr<TBytesStream> myBytesStream(new TBytesStream(myBytes));
     
    long res=1;
    	while(res>0) {
    	try{
    		res = myBytesStream->CopyFrom(LFileStream.get(), 60000);
    		}
     
    	 catch(char *excp){
     
    	 	}
    	}

  2. #2
    Membre Expert
    Avatar de DjmSoftware
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Mars 2002
    Messages
    1 044
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

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

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 044
    Billets dans le blog
    1
    Par défaut
    Salut
    pourquoi utilise tu une taille fixe de 60000
    il serait beaucoup plus simple de calculer à partir de la taille de ton fichier un nombre constant de blocs

    ex d'algo :si ton fichier fait 142000 octets tu obtiens
    2 blocs de 60000 et un bloc 22000

    cdlt
    vous trouverez mes tutoriels à l'adresse suivante: http://djmsoftware.developpez.com/
    je vous en souhaite une excellente lecture ...

    A lire : Les règles du forum

  3. #3
    Membre très actif Avatar de Argol_Medusa
    Homme Profil pro
    Ingénieur Radiofréquences
    Inscrit en
    Août 2005
    Messages
    208
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur Radiofréquences
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 208
    Par défaut
    Concrètement, que veux-tu faire exactement en fait ?
    Gros fichier c'est quelle taille ?

    Voici une manière possible d'utiliser des MemoryStream pour lire un gros fichier :

    Code : 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
    TMemoryStream *a;
    a = new TMemoryStream();
    a->LoadFromFile("c:\\test.exe");
     
    TMemoryStream *Destination;
    Destination = new TMemoryStream();
     
    unsigned long int taille=456;
    Destination->CopyFrom(a,taille);
    Destination->Seek(0,0);
     
    // faire ce que l'on veut ici avec la memory stream de Destination
     
    delete a;
    delete Destination;
    a=NULL;
    Destination=NULL;

  4. #4
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 081
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 081
    Par défaut
    Si c'est une Exception Delphi, c'est plutôt cela le catch

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    catch(Exception *e) 
    catch(const Exception &e)
    get() c'est lié à auto_ptr ?

    Evite le c_str(), la VCL gère des AnsiString, String, UnicodeString naturellement, c_str() doit être utilisé uniquement si l'on a explicitement besoin d'un char* pour une API Windows par exemple

    Utilise plutôt des String que des std::string en C++Builder
    Si fileName est String, ceci est suffisant ... new TFileStream(fileName, fmOpenRead));.


    Sinon, il faut savoir que c'est le comportement par défaut de LoadFromFile avec TStream, il charge le fichier par bloc comme je l'ai expliqué dans le sujet TMemoryStream : incompréhension

    Citation Envoyé par ShaiLeTroll Voir le message
    Pour LoadFromStream, tu peux effectivement copier un TFileStream vers un TMemoryStream, cela utilise CopyFrom en interne
    Pour LoadFromFile, c'est ni plus ni moins qu'un wrapper de TFileStream\LoadFromStream
    CopyFrom utilise un tampon de 60Kio pour la méthode abstraite Read() et boucle jusqu'à ce que la quantitée de donnée restant à copier atteignent zéro
    Si tu veux copier plusieurs Gio cela fera via quelques milliers d'itérations de 60Kio


    Si au final, tout est copié dans le TMemoryStream, je ne vois pas l'intérêt de le faire à la main !

    L'intérêt de lire par bloc, c'est d'effectuer une manipulation des données à chaque itération, sans avoir en mémoire l'ensemble du fichier


    @Argol, tu charges entièrement le fichier mémoire avec ton code pour au final ne lire que 456 octets, pour un réel chargement partiel

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    TFileStream *FS = new TFileStream ("c:\\test.exe", fmOpenRead);
    try
    {
      Byte Buffer[456];  
      FS->ReadBuffer(Buffer, sizeof(Buffer));    
     
      // faire ce que l'on veut ici avec la memory Buffer
    }
    __finally
    {
      delete FS ;
    }
    Et si l'on absolument ton continué avec un Stream

    Code : 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
    TFileStream *FS = new TFileStream("c:\\test.exe", fmOpenRead);
    try
    {
      TMemoryStream *MS = new TMemoryStream();
      try
      {
         MS->CopyFrom(Buffer, 456); // va appeler Read et lire ce qui est nécessaire   
         MS->Seek(0,0);
         // faire ce que l'on veut ici avec la memory stream de Destination
     
     
      }
      __finally
      {
        delete MS ;
      }
    }
    __finally
    {
      delete FS ;
    }
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  5. #5
    Membre éclairé
    Profil pro
    lkjlgj
    Inscrit en
    Février 2007
    Messages
    255
    Détails du profil
    Informations personnelles :
    Localisation : Angola

    Informations professionnelles :
    Activité : lkjlgj

    Informations forums :
    Inscription : Février 2007
    Messages : 255
    Par défaut
    Merci Argol Medusa et ShaiLeTroll.

    J'imprime vos suggestions pour les étudier.

    En fait, mon souci c'est que là où TStringList->LoadFromFile fonctionne parfaitement pour de petits fichiers sans que j'aie à me soucier de leur encodage, dès lors que le fichier en question est plus gros (en l'occurrence 500G d'UTF-8) ça marche plus aussi bien.

    Donc je lorgne du coté du file mapping puis des TStream qui me semblent plus simples à saisir.

    En gros j'essaie d'écrire un TStringList->LoadFromFile... par blocs.
    ...et entre chaque lecture, je tokenize le bloc en mots.

  6. #6
    Membre éclairé
    Profil pro
    lkjlgj
    Inscrit en
    Février 2007
    Messages
    255
    Détails du profil
    Informations personnelles :
    Localisation : Angola

    Informations professionnelles :
    Activité : lkjlgj

    Informations forums :
    Inscription : Février 2007
    Messages : 255
    Par défaut
    J'essaie donc d'appliquer vos recettes mais je n'arrive pas à intercepter l'erreur du CopyFrom malgrè le try / catch.
    Ci-dessous,pour un fichier de taille 129000, la boucle while tourne deux fois puis l'impossibilité de lire 60000 bytes une troisième fois provoque une erreur de type
    "class EReadError with message Stream read error".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    	unsigned long int taille=60000;
     
       bool cont=true;
       while(cont){
    	try{
    		Destination->CopyFrom(a, taille);
    		Destination->Seek(0,0);
    		}
     
    	catch(const Exception &e){
    		 cont=false;
    	}
    	}

  7. #7
    Membre très actif Avatar de Argol_Medusa
    Homme Profil pro
    Ingénieur Radiofréquences
    Inscrit en
    Août 2005
    Messages
    208
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur Radiofréquences
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 208
    Par défaut
    Oups, j'étais en train d'écrire quand tu as posté.
    Je vois mieux l'application maintenant.

    Tu as 500 Go d'UTF-8 ... hé bé ... moi qui croyait avoir de gros fichier avec mes 10Go !

    A priori il est clair que dans ton cas il ne faut pas essayer de travailler en un seul fichier en mémoire, tu vas exploser tes TStringList ou TMemoryStream.

    Utiliser des TFileStream pour charger morceau par morceau et copier dans des TStringList me semble cohérent.

    Cependant, tu peux essayer séparer ton fichier de 500Go en plusieurs fichiers et/ou compresser en zip ( le texte se compresse TRES bien, tu pourrais facilement passer à 20 Go ), et de le décompresser en live en faisant une classe genre "TSpecialeFileStream", c'est ce que j'ai fais il y a quelques semaines ).
    Ca permettra de gagner en place si le temps de traitement n'est pas critique ( utilisation d'une TZipForge par exemple )

  8. #8
    Membre très actif Avatar de Argol_Medusa
    Homme Profil pro
    Ingénieur Radiofréquences
    Inscrit en
    Août 2005
    Messages
    208
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur Radiofréquences
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 208
    Par défaut
    Cela rejoint notre discussion d'il y a quelques semaines (dont tu as mis le lien,Shaï).

    Effectivement c'est une bonne remarque, l'emploie d'un TFileStream semble plus judicieux ici (sauf cas particuliers, suivant ce que tu vas en faire une fois en mémoire ).

    Par contre ça te bloque peut-être le fichier en ouverture ( à vérifier, c'est même pas sur suivant comment ça a été codé ), donc prudence sur ce point dans le cas d'accès multiples.

    Sinon oui lire le gros fichier pour seulement 300 octets, il faut qu'il y ait un intérêt, d'où ma question "qu'est-ce que tu veux faire exactement avec ça?".

    Si tu dois pouvoir lire/écrire n'importe quel bloc du fichier à n'importe quel moment pour application temps réel (vidéo/audio/base de donnée importante), alors oui ça a un intérêt.

    Sinon, le TFileStream ira très bien.

Discussions similaires

  1. Réponses: 6
    Dernier message: 24/10/2005, 20h12
  2. [CR11] Formule, If statement et valeur retournée
    Par KrusK dans le forum Formules
    Réponses: 3
    Dernier message: 07/09/2005, 12h12
  3. valeur retournée par un .js
    Par astrofiles dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 09/08/2005, 10h20
  4. valeur retournée d'une fonction
    Par jokos2000 dans le forum Oracle
    Réponses: 8
    Dernier message: 29/06/2005, 12h21
  5. select avec un nombre limité de valeurs retournées
    Par felix79 dans le forum Langage SQL
    Réponses: 5
    Dernier message: 23/12/2004, 15h16

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