Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 13 sur 13
  1. #1
    Membre du Club
    Inscrit en
    février 2007
    Messages
    233
    Détails du profil
    Informations forums :
    Inscription : février 2007
    Messages : 233
    Points : 48
    Points
    48

    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 :
    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
    Rédacteur/Modérateur
    Avatar de DjmSoftware
    Homme Profil pro
    Responsable de compte
    Inscrit en
    mars 2002
    Messages
    654
    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 : 654
    Points : 1 408
    Points
    1 408

    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
    A lire : Les règles du forum

  3. #3
    Membre actif Avatar de Argol_Medusa
    Homme Profil pro Yann
    Ingénieur Radiofréquences
    Inscrit en
    août 2005
    Messages
    194
    Détails du profil
    Informations personnelles :
    Nom : Homme Yann
    Localisation : France

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

    Informations forums :
    Inscription : août 2005
    Messages : 194
    Points : 174
    Points
    174

    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 :
    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;
    Désolé, on savait pas que c'était impossible, alors on l'a fait

  4. #4
    Expert Confirmé Sénior Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    juillet 2006
    Messages
    10 037
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : juillet 2006
    Messages : 10 037
    Points : 12 856
    Points
    12 856

    Par défaut

    Si c'est une Exception Delphi, c'est plutôt cela le catch

    Code :
    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 :
    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 :
    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

    Halte à la ségrégation des Cinémas, VO sur Paris, VF en Banlieue, Abonnement résilié !

  5. #5
    Membre du Club
    Inscrit en
    février 2007
    Messages
    233
    Détails du profil
    Informations forums :
    Inscription : février 2007
    Messages : 233
    Points : 48
    Points
    48

    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 actif Avatar de Argol_Medusa
    Homme Profil pro Yann
    Ingénieur Radiofréquences
    Inscrit en
    août 2005
    Messages
    194
    Détails du profil
    Informations personnelles :
    Nom : Homme Yann
    Localisation : France

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

    Informations forums :
    Inscription : août 2005
    Messages : 194
    Points : 174
    Points
    174

    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.
    Désolé, on savait pas que c'était impossible, alors on l'a fait

  7. #7
    Membre du Club
    Inscrit en
    février 2007
    Messages
    233
    Détails du profil
    Informations forums :
    Inscription : février 2007
    Messages : 233
    Points : 48
    Points
    48

    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 :
    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;
    	}
    	}

  8. #8
    Membre actif Avatar de Argol_Medusa
    Homme Profil pro Yann
    Ingénieur Radiofréquences
    Inscrit en
    août 2005
    Messages
    194
    Détails du profil
    Informations personnelles :
    Nom : Homme Yann
    Localisation : France

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

    Informations forums :
    Inscription : août 2005
    Messages : 194
    Points : 174
    Points
    174

    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 )
    Désolé, on savait pas que c'était impossible, alors on l'a fait

  9. #9
    Expert Confirmé Sénior Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    juillet 2006
    Messages
    10 037
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : juillet 2006
    Messages : 10 037
    Points : 12 856
    Points
    12 856

    Par défaut

    Moi qui pensait que l'on était limité à 40Go pour un fichier !

    Pourquoi utiliser CopyFrom ?
    Si tu veux traiter bloc par bloc inutile de copier dans un autre stream pour au final tout accumuler en mémoire (ce que fait LoadFromFile pour info)

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    std::auto_ptr<TFileStream> LFileStream(new TFileStream(fileName.c_str(), fmOpenRead));
     
      do 
      {
        Byte Buffer[65536];  
        RealRead = FS->Read(Buffer, sizeof(Buffer));    
        for(int i = 0; i < RealRead; i++)
        {
          Traitement de Buffer[i]
        }
      } while (RealRead > 0);
    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

    Halte à la ségrégation des Cinémas, VO sur Paris, VF en Banlieue, Abonnement résilié !

  10. #10
    Membre du Club
    Inscrit en
    février 2007
    Messages
    233
    Détails du profil
    Informations forums :
    Inscription : février 2007
    Messages : 233
    Points : 48
    Points
    48

    Par défaut

    Merci Shai LeTroll,

    Ton exemple fonctionne parfaitement bien et me convient puisque la valeur retour realread
    me permet de garder un oeil sur le nombre de caractères lus effectivement à chaque passage dans la boucle.

    Aussi, il n'y a plus d'erreur de lecture dans le stream !

    Reste le problème de la conversion de bytes à string (problème que TStringList->LoadFromFile gère automatiquement).

    Si je dois décoder l'UTF-8 à la main, je sais que je dois "sauter" les 3 caractères de BOM
    au début du fichier puis décoder chaque caractère pour ensuite tokenizer la chaîne.

    Vous me conseillez de transformer les bytes en UnicodeString, wstring, etc. ?
    Merci encore !

  11. #11
    Expert Confirmé Sénior Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    juillet 2006
    Messages
    10 037
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : juillet 2006
    Messages : 10 037
    Points : 12 856
    Points
    12 856

    Par défaut

    Que contient de ton fichier, est-ce QUE du texte ?
    Si UTF8, en buffer, faudra penser à gérer un caractère dont le 1er octet à la fin d'un buffer et le 2nd ou 3eme un début du buffer suivant !

    Ton fichier fera vraiment 500 Go ?
    500Go = 5 000 000 000 o
    500 Gio = 5 368 709 120 o

    Les fonctions UTF8Encode et UT8Decode sont prévu pour cela !
    Tu as d'autres en XE2, je n'ai pas le nom en tête, je les ai cité dans un autre sujet
    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

    Halte à la ségrégation des Cinémas, VO sur Paris, VF en Banlieue, Abonnement résilié !

  12. #12
    Membre du Club
    Inscrit en
    février 2007
    Messages
    233
    Détails du profil
    Informations forums :
    Inscription : février 2007
    Messages : 233
    Points : 48
    Points
    48

    Par défaut

    Merci ShaiLeTroll !

    Oui, oui, le fichier en entrée fait bien 500G (actuellement il mesure 210G de texte pur mais croît régulièrement).

    Aussi, il faut effectivement traiter les caractères à 2/3 bytes qui seraient tronqués par la taille du buffer de lecture.
    J'avais déjà écrit une fonction de lecture de gros fichiers (ANSI/ASCII) qui gère bien le
    problème du tronquage de mots (voir fonction ci-dessous).

    Je vais donc essayer de faire qqc de semblable pour les caractères UTF8 à moins que je trouve une fonction XE2. Je crois avoir vu des choses adéquates ici.

    Code :
    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
     
     
    int TForm1::readBigFile()
    {
    	char buffer[BUF_SIZE];
    	long offset, blocksread=0, charsread;
    	std::streampos fpos;
     
    	ifstream myFile (fileName.c_str(), ios::in | ios::binary);
     
    	while (!myFile.eof()) {
     
    		   myFile.read (buffer, BUF_SIZE);
    		   charsread = myFile.gcount();
    		   fpos = myFile.tellg();
     
    		   // Buffer was filled with characters
    		   if(charsread == BUF_SIZE){
     
    				offset=1;
     
    				// make sure buffer doesn't truncate a token (move back in buffer until first delimiter)
    				if(!isDelimiter(buffer[myFile.gcount()-offset])){
    					while(myFile.gcount()>=offset && !isDelimiter(buffer[myFile.gcount()-offset]))
    						offset++;
    					}
     
    				// make sure buffer ends with whole word (move back in buffer to first non-delimiter character)
    				if(isDelimiter(buffer[myFile.gcount()-offset])){
    					while(myFile.gcount()>=offset && isDelimiter(buffer[myFile.gcount()-offset]))
    						offset++;
    					offset--;   	// Preserve last non-delimiter character
    					}
     
    				// exclude (erase) all characters not to be read
    				for(long i=BUF_SIZE-offset; i<BUF_SIZE;i++)
    					buffer[i]='\0';
     
    				fpos = fpos -offset;
    				myFile.seekg(fpos);
    				}
     
    			// Buffer was not filled to the maximum (end of file)
    			else{
    				for(long i=myFile.gcount(); i<BUF_SIZE; i++)
    					buffer[i]='\0';
    				}
     
    	}
       myFile.close();
    }

  13. #13
    Membre du Club
    Inscrit en
    février 2007
    Messages
    233
    Détails du profil
    Informations forums :
    Inscription : février 2007
    Messages : 233
    Points : 48
    Points
    48

    Par défaut

    Bonjour !

    Autre tentative de lire un gros fichier en UTF8...

    Je parviens à lire assez rapidement un énorme fichier avec la combinaison TStreamReader + ReadBlock qui s'avère plus véloce que ReadLine() et Read().

    TOUTEFOIS, j'ai un souci pour repositionner mon pointeur de fichier après lecture de chaque bloc (les blocs ont une taille fixe de 500 octets).

    En effet, je tente de lire sur le fichier des séquences de mots en évitant de lire des mots à moitié en les tronquant.
    Donc, je scrute toujours la fin de mon bloc lu pour vérifier qu'il se termine par un blanc. Le cas échéant, je tronque jusqu'à tomber sur un espace et alors je colle à cette emplacement un '\0' pour terminer la chaine proprement.

    Reste à répercuter cette marche arrière sur le pointeur de fichier de manière à ce qu'à la prochaine passe de lecture celle-ci reprenne à partir du blanc.

    Or, malgré différents tests, le décalage espéré n'a pas lieu : les caractères écartés à la lecture ne sont pas intégrés à la lecture suivante !?!?!
    La lecture reprend là oú elle s'est finie.

    Autres tests :
    J'ai essayé avec stReader->DiscardBufferedData() mais ça envoie le pointeur encore plus loin en avant dans le fichier !?!
    Que je prenne en compte ByteCount ou pas ne change rien...

    Si quelqu'un a une idée... MERCI !


    ----------- Exemple :
    Considérons l'extrait de texte suivant :
    Code :
    1
    2
    3
     
    <CHAPTER ID=1> Reprise de la session <SPEAKER ID=1 NAME="La Présidente"> Je déclare reprise la session du Parlement européen qui avait été interrompue le vendredi 17 décembre dernier et je vous renouvelle tous mes voeux en espérant que vous avez passé de bonnes vacances.
    Comme vous avez pu le constater, le grand "bogue de l'an 2000" ne s'est pas produit. En revanche, les citoyens d'un certain nombre de nos pays ont été victimes de catastrophes naturelles qui ont vraiment été terribles. Vous avez souhaité un débat à ce sujet dans les prochains jours, au cours de cette période de session. En attendant, je souhaiterais, comme un certain nombre de collègues me l'ont demandé, que nous observions une minute de silence pour toutes les victimes, des tempêtes notamment, dans les différents pays de l'Union européenne qui ont été touchés. Je vous invite à vous lever pour cette minute de silence.
    -------------PASSE #1
    Bloc lu sur le fichier :
    <CHAPTER ID=1> Reprise de la session <SPEAKER ID=1 NAME="La Présidente"> Je déclare reprise la session du Parlement européen qui avait été interrompue le vendredi 17 décembre dernier et je vous renouv
    Bloc tronqué :
    <CHAPTER ID=1> Reprise de la session <SPEAKER ID=1 NAME="La Présidente"> Je déclare reprise la session du Parlement européen qui avait été interrompue le vendredi 17 décembre dernier et je vous

    Donc, "renouv" a été volontairement écarté et devrait être relu à la passe suivante mais ce n'est pas ce qui se passe :

    -------------PASSE #2
    Bloc lu sur le fichier :
    elle tous mes voeux en espérant que vous avez passé de bonnes vacances. Comme vous avez pu le constater, le grand "bogue de l'an 2000" ne s'est pas produit. En revanche, les citoyens d'un certain
    Bloc tronqué :
    elle tous mes voeux en espérant que vous avez passé de bonnes vacances. Comme vous avez pu le constater, le grand "bogue de l'an 2000" ne s'est pas produit. En revanche, les citoyens d'un certain


    J'ai

    Code :
    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
     
    	TStreamReader* stReader = new TStreamReader("./fr_merged.txt", TEncoding::UTF8);
    	stReader->OwnStream();
     
    	wchar_t ctoken;
    	UnicodeString ltoken;
    	TCharArray buffer;
    	unsigned long bufferMaxSize=200;
    	unsigned long bufferReduced;
    	buffer.set_length(bufferMaxSize);
     
    	UnicodeString texte="";
    	Memo1->Text=texte;
     
       	long ByteCount=stReader->CurrentEncoding->GetByteCount(buffer);
       	long streamOffset;
       	unsigned long fposition;
     
       	while (!stReader->EndOfStream){
     
    		// Lire des blocs de 500 bytes
    		stReader->ReadBlock(buffer, 0, buffer.Length);
     
    		if(buffer.Length==bufferMaxSize){
     
    		// Si le dernier char n'est pas un blanc...
    		if (buffer[buffer.Length-1] !=' '){
    			bufferReduced=buffer.Length-1;
    			while(bufferReduced>0){
    				if(buffer[bufferReduced-1]==' '){
    					// Tronquer le buffer après le blanc
    					buffer[bufferReduced]='\0';
    					break;
    					}
    				bufferReduced--;
    				}
     
    			// Repositionner le pointeur fichier quelques bytes avant la position actuelle
    			streamOffset=(bufferMaxSize-bufferReduced)*ByteCount;
    			streamOffset=-streamOffset;
    			stReader->BaseStream->Seek((__int64)streamOffset, soFromCurrent );
    			// Vider le buffer 
    			stReader->DiscardBufferedData();
    			}
    			}
     
    		// Imprimer le bloc de texte tronqué
    		texte = &buffer[0];
    		texte +="\r\n\r\n";
    		Memo1->Text = Memo1->Text + texte;
    	   }
     
     
    	if(stReader){
    		stReader->Close();
    		delete stReader->BaseStream;
    		delete stReader;
    		stReader=NULL;
    		}

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •