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

Lazarus Pascal Discussion :

[Wiki] Erreur dans http://wiki.freepascal.org/File_Handling_In_Pascal


Sujet :

Lazarus Pascal

  1. #1
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 732
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 732
    Points : 15 137
    Points
    15 137
    Par défaut [Wiki] Erreur dans http://wiki.freepascal.org/File_Handling_In_Pascal
    Bonjour,

    si quelqu'un a un compte, ça serait bien qu'il poste ce qui suit dans la page "discussion" :
    +++
    Wrong test in last example of Generic files of any type (starting with "With larger files of many Gb, ...")

    Hello,
    The test
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      while TotalBytesRead <= FileStream.Size do  // While the amount of data read is less than or equal to the size of the stream do
    never terminates... Should be
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      while TotalBytesRead < FileStream.Size do  // While the amount of data read is less than to the size of the stream do
    because TotalBytesRead will never reach FileStream.Size : starting at 0, TotalBytesRead grows up to FileStream.Size -1 !

    Tested with
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
        while TotalBytesRead < FileStream.Size do  // While the amount of data read is less than to the size of the stream do
        begin
          BytesRead := FileStream.Read(Buffer,sizeof(Buffer));  // Read in 4096 of data
          inc(TotalBytesRead, BytesRead);                       // Increase TotalBytesRead by the size of the buffer, i.e. 4096 bytes
          // Do something with Buffer data
        end;
      finally
        FileStream.Free
      end;
      ShowMessage(IntToStr(TotalBytesRead)); // Shows the same value as FileSize
    end;
    +++
    Merci et bon week-end,
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  2. #2
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 700
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 700
    Points : 13 138
    Points
    13 138
    Par défaut
    Problème il y a mais ton explication est fausse. TotalBytesRead est le nombre d'octets lus et non l'indice du dernier (FileStream.Size -1).
    TotalBytesRead va (doit) atteindre FileStream.Size mais lorsqu'ils sont égaux, il faut sortir de la boucle puisque TotalBytesRead ne sera plus incrémenté et la condition toujours vraie.

    Ce serait plus simple de tester BytesRead.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    while TRUE do
    begin
      BytesRead := FileStream.Read(Buffer,sizeof(Buffer));
      if BytesRead = 0 then Break;
     
      // Do something with Buffer data
    end;

  3. #3
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 732
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 732
    Points : 15 137
    Points
    15 137
    Par défaut
    Merci de t'être penché là-dessus, mais j'avoue ne pas bien comprendre ton explication...

    Citation Envoyé par Andnotor Voir le message
    TotalBytesRead va (doit) atteindre FileStream.Size
    Pour moi ça semble impossible dans la mesure où ce compteur est initialisé à 0 et incrémenté du nombre de bytes lus. Je l'ai d'ailleurs écrit :
    Citation Envoyé par Jipété Voir le message
    TotalBytesRead will never reach FileStream.Size : starting at 0, TotalBytesRead grows up to FileStream.Size -1
    Avant de poster, ce matin, j'ai fait un test avec un fichier de 146 bytes et un autre de 3578, ayant dimensionné l'array of Bytes à [0..1023].

    Dans le 1er cas le ShowMessage(IntToStr(TotalBytesRead)); m'a bien indiqué 146 et dans l'autre 3578 : je suis donc sorti de la boucle dans les 2 cas, et j'ai bien lu le bon nombre d'octets à chaque fois : il doit y avoir un mécanisme, une sécurité dans le FileStream.Read qui fait qu'on ne peut pas dépasser la taille du fichier.

    D'ailleurs, avant de poster cette réponse, j'ai rajouté cette ligne avant le finally :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ShowMessage(IntToStr(FileStream.Position) + ' ' + IntToStr(FileStream.Size));
    et elle me donne 146 146 avec le petit fichier et 3578 3578 avec le grand, on s'en doutait.
    Mais des fois c'est mieux de l'avoir sous les yeux ("je ne crois que ce que je vois", )

    Que dire de plus ? Que le FileStream.Size correspond exactement à la taille du fichier alors qu'il n'y a pas d'instruction de (re)dimensionnement du flux dans ces quelques lignes de code, et que les gens de FPC/Laz devraient se pencher sur le fait que la FileStream.position est un peu border line, là, heureusement qu'on a fini avec le flux, à ce moment-là,

    Bon, j'ai fait un test avec tes indications, et le résultat est strictement le même (et heureusement !) Je disais plus haut qu' "il doit y avoir un mécanisme, une sécurité dans le FileStream.Read qui fait qu'on ne peut pas dépasser la taille du fichier" et c'est ce que tu "sors" de la boîte noire du FileStream.Read en "l'exposant" avec ton test if BytesRead = 0 then Break;.

    Partant du principe / de l'idée que TotalBytesRead pourrait être utilisé comme une sécurité en fin de lecture, on se retrouve à choisir entre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
        while TotalBytesRead < FileStream.Size do  // original While the amount of data read is less than or equal to the size of the stream do
        begin
          BytesRead := FileStream.Read(Buffer, sizeof(Buffer)); // Read in 1024 bytes of data
          inc(TotalBytesRead, BytesRead);                       // Increase TotalBytesRead by the size of the buffer, i.e. 1024 bytes
          // Do something with Buffer data
        end;
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
        while TRUE do  // Andnotor -- While the amount of data read is less than or equal to the size of the stream do
        begin
          BytesRead := FileStream.Read(Buffer, sizeof(Buffer)); // Read in 1024 bytes of data
          if BytesRead = 0 then Break;
          inc(TotalBytesRead, BytesRead);                       // ligne conservée Increase TotalBytesRead by the size of the buffer, i.e. 1024 bytes
          // Do something with Buffer data
        end;
    Ces deux boucles font àmha strictement le même boulot, et le reproche qu'on pourrait faire, c'est un léger flou au niveau d'un commentaire pas toujours vrai : inc(TotalBytesRead, BytesRead); // Increase TotalByteRead by the size of the buffer, i.e. 1024 bytes car il est quand même extrêmement rare de ne lire que des fichiers dont la taille est exactement un multiple de 4096, non ?
    Sans compter ceux qui sont plus petits,
    Ça serait mieux d'avoir inc(TotalBytesRead, BytesRead); // Increase TotalBytesRead by the number of bytes read, comme le nom l'indique, tout simplement.

    D'autres avis ?

    EDIT :
    En fait, la bonne question c'est "pourquoi ne sort-on pas de la boucle si le test est while TotalBytesRead <= FileStream.Size do ?" puisqu'on voit bien, avec le ShowMessage, que TotalBytesRead arrive à la valeur de FileStream.Size.


    Le piège dans lequel je suis tombé (je me les tends tout seul, maintenant !), c'est que cette variable est initialisée à 0, puis incrémentée du nombre d'octets lus (en une ou plusieurs fois), et je sens que partant d'un truc simple, on va encore se retrouver à s'arracher les cheveux...

    Pour en avoir le cœur net, j'ai fait
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var
      fss: int64;
    begin
        //...
        fss := FileStream.Size; // pour avoir une valeur lisible en pas-à-pas
        while TotalBytesRead <= fss do  // While the amount of data read is less than or equal to the size of the stream do
        begin
          BytesRead := FileStream.Read(Buffer, sizeof(Buffer)); // Read in 1024 bytes of data
          inc(TotalBytesRead, BytesRead);                       // Increase TotalBytesRead by the size of the buffer, i.e. 1024 bytes
          // Do something with Buffer data
        end;
    et je ne sors pas de la boucle !

    En pas-à-pas je mets la souris sur TotalBytesRead et je lis 146 (avec le petit fichier), je la mets sur fss et je lis aussi 146, conclusion "<=" ne fonctionne pas, donc !

    EDIT2 :
    Si si, ça fonctionne :
    En français, tant que TotalBytesRead est inférieur à la taille du fichier ou égal à la taille du fichier lis des octets.
    Et c'est bien ce qui se passe : quand on arrive à TotalByteRead = taille du fichier on reste dans la boucle.

    Bien vu, Andnotor !

    Bon, je mets ça au propre.
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  4. #4
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 732
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 732
    Points : 15 137
    Points
    15 137
    Par défaut
    Citation Envoyé par Jipété Voir le message
    Bon, je mets ça au propre.
    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
    var
      //...       
      MustRead: boolean;
    begin
        //...
        FileStream.Position := 0;  // Ensure you are at the start of the file
        MustRead := True;
        while MustRead do
        begin
          BytesRead := FileStream.Read(Buffer, sizeof(Buffer)); // Read in sizeof(Buffer) bytes of data
          if BytesRead = 0 then MustRead := False; // fin de fichier ou erreur -->
          // analyser TotalBytesRead, à comparer avec FileStream.Size
          inc(TotalBytesRead, BytesRead);                       // Increase TotalBytesRead by the number of bytes read
          // Do something with Buffer data
        end;
      finally                          
        FileStream.Free
      end;
      ShowMessage(IntToStr(TotalBytesRead)); // 146 ou 3578
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  5. #5
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 631
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 631
    Points : 10 559
    Points
    10 559
    Par défaut
    @Jipété ton code est mauvais (Édit : il y a un incrément et un traitement fait en plus)


    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
    22
    23
    24
    25
    26
    27
    28
    var
      //...       
      MustRead: boolean;
    begin
        //...
     
        FileStream.Position := 0;  // Ensure you are at the start of the file
        MustRead := True;
     
        while MustRead do
        begin
          BytesRead := FileStream.Read(Buffer, sizeof(Buffer)); // Read in sizeof(Buffer) bytes of data
     
          if BytesRead <> 0
          then
              begin
                  // analyser TotalBytesRead, à comparer avec FileStream.Size
                  inc(TotalBytesRead, BytesRead);                       // Increase TotalBytesRead by the number of bytes read
                  // Do something with Buffer data
             end;
         else
             MustRead := False; // fin de fichier ou erreur -->
        end;
      finally                          
        FileStream.Free
      end;
     
      ShowMessage(IntToStr(TotalBytesRead)); // 146 ou 3578

  6. #6
    Expert confirmé
    Avatar de BeanzMaster
    Homme Profil pro
    Amateur Passionné
    Inscrit en
    Septembre 2015
    Messages
    1 899
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Amateur Passionné
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Septembre 2015
    Messages : 1 899
    Points : 4 346
    Points
    4 346
    Billets dans le blog
    2
    Par défaut
    Hello, tu n'as pas besoins de ta variable mustread l'exemple d AndnotOr fait exactement la même chose et est bien plus simple, courte et lisible. Pourquoi compliquer ton code ? De plus MustRead prend de la place en mémoire, ce qui ne sert à rien même si c'est juste quelques octets. Le mustRead pourrait avoir son utilité seulement si tu développes la partie // Do something with Buffer data et ou tu devrais gérer des cas spéciaux et ou tu devrait sortir de la boucle en cas d'erreur et encore le nom de mustread serqit inapproprié un nom du genre HasError serait mieux

    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
    22
    23
    24
    25
    26
    27
     
    Var
      HasError : Boolean;
    begin
       Try
          FileStream.Position := 0;  // Ensure you are at the start of the file
          HasError := False
          while True  do
          begin
            BytesRead := FileStream.Read(Buffer, sizeof(Buffer)); // Read in sizeof(Buffer) bytes of data
            if BytesRead = 0 then Break; // fin de fichier ou erreur -->
            inc(TotalBytesRead, BytesRead);                       // Increase TotalBytesRead by the number of bytes read
            // Do something with Buffer data
            if Buffer[0]<>'A' then 
            begin
              HasError := True;
              Break;
            end;
          end;
      finally                          
        if Not(HasError) then if TotalBytesRead <> FileStream.Size then HasError :=True;
        FileStream.Free
      end;
      if HasError then ShowMessage('ERREUR') 
      else
        ShowMessage(IntToStr(TotalBytesRead)); // 146 ou 3578
    end;
    A noter également que TFileStream.Read en cas d'erreur de lecture te renverra un nombre plus petit que zero. Zero signifera que la fin du flux est atteinte dans le cas d'un TFileStream cf : http://lazarus-ccr.sourceforge.net/d...ream.read.html

    If the operating system reports an error while reading from the handle, -1 is returned.
    • "L'Homme devrait mettre autant d'ardeur à simplifier sa vie qu'il met à la compliquer" - Henri Bergson
    • "Bien des livres auraient été plus clairs s'ils n'avaient pas voulu être si clairs" - Emmanuel Kant
    • "La simplicité est la sophistication suprême" - Léonard De Vinci
    • "Ce qui est facile à comprendre ou à faire pour toi, ne l'est pas forcément pour l'autre." - Mon pèrei

    Mes projets sur Github - Blog - Site DVP

  7. #7
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 631
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 631
    Points : 10 559
    Points
    10 559
    Par défaut
    Citation Envoyé par BeanzMaster Voir le message
    Hello, tu n'as pas besoins de ta variable mustread l'exemple d AndnotOr fait exactement la même chose et est bien plus simple, courte et lisible. Pourquoi compliquer ton code ?
    C'est simple c'est pour le compilateur .
    En ajoutant une variable, il n'y a qu'un seul chemin avec un while + test. Alors que l'autre tu as 2 chemins, la boucle infinie et la suite/ la fin.

    Après, il faudrait comparer le binaire et peut-être qu'il n'y a pas de différence. Peut-être que le compilateur va comprendre/ optimiser la boucle infinie + break.

  8. #8
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 732
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 732
    Points : 15 137
    Points
    15 137
    Par défaut
    Bon, j'ai tout bien réfléchi, comparé, testé, je combine le meilleur des trois (même si je n'aime pas cette boucle infinie while TRUE [ça me fait peur ce truc]) et ça donne ça :

    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
    22
    var
      //...
      HasError: Boolean;
    begin
        //...
        FileStream.Position := 0;  // Ensure you are at the start of the file
        HasError := False
        while TRUE do
        begin
          BytesRead := FileStream.Read(Buffer, sizeof(Buffer)); // Read in sizeof(Buffer) bytes of data
          if BytesRead = 0 then Break; // fin de fichier ou erreur de lecture -->
          // analyser TotalBytesRead, à comparer avec FileStream.Size
          inc(TotalBytesRead, BytesRead);                       // Increase TotalBytesRead by the number of bytes read
          // Do something with Buffer data
        end;
      finally
        HasError := (TotalBytesRead <> FileStream.Size);
        FileStream.Free
      end;
      if HasError
      then ShowMessage('ERREUR')
      else ShowMessage(IntToStr(TotalBytesRead)); // 146 ou 3578
    Je crois qu'on est bien, là, non ?

    MP pour Jérome :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    //  if Not HasError then // test inutile, HasError EST déjà à False
          if TotalBytesRead <> FileStream.Size then HasError := True;
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  9. #9
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 732
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 732
    Points : 15 137
    Points
    15 137
    Par défaut
    Citation Envoyé par Jipété Voir le message
    Je crois qu'on est bien, là, non ?
    La nuit porte conseil...

    On a zappé le fait que ce n'est pas moi qui suis en erreur, c'est le wiki, et c'est lui qu'il faut corriger !

    L'erreur est dans cette ligne, dans cette boucle dont on ne peut sortir :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        while TotalBytesRead <= FileStream.Size do
    et le moyen que j'avais trouvé, tout en conservant l'idée de base, c'est de juste modifier le test en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        while TotalBytesRead < FileStream.Size do
    qu'on peut traduire par "tant qu'on n'a pas lu tous les bytes on continue à lire".

    La chose ennuyeuse qu'on découvre maintenant, c'est la suite, qui ne nous prémunit pas d'une erreur de lecture :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
      begin
        BytesRead := FileStream.Read(Buffer,sizeof(Buffer));  // Read in 4096 of data
        inc(TotalBytesRead, BytesRead);                       // Increase TotalBytesRead by the size of the buffer, i.e. 4096 bytes
        // Do something with Buffer data
      end;
    Car si on lit 0 bytes là-dedans, on n'incrémentera pas le TotalBytesRead et donc on ne sortira pas (sauf si l'erreur de lecture est suffisamment violente, mais ceci est une autre histoire).

    Une manière de sécuriser la chose pourrait être de faire ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
      begin
        BytesRead := FileStream.Read(Buffer,sizeof(Buffer));  // Read in sizeof(Buffer) of data
        if BytesRead > 0 then                                 // Security check
        begin
          inc(TotalBytesRead, BytesRead);                     // Increase TotalBytesRead by the number of bytes read
          // Do something with Buffer data
        end
        else                                                  // Something wrong or EOF
        if TotalBytesRead <> FileStream.Size then             // Something really wrong! 
        begin
          ShowMessage('Error');  // manages error
          Break;                 // exit loop
        end;
      end;
    En faisant ainsi, on reste dans les clous du code d'origine et on y ajoute un petit plus qui ne peut pas faire de mal.

    +++
    Et pendant que j'y suis, j'ai relu hier une note prise chez SO, qui a l'air très intéressante (peut-être juste pour les windowsiens) en ce qui concerne certaines optimisations, qu'on en juge :

    If you have this kind of codes

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      while Stream.Position < Stream.Size do
    You can optimize it by caching the FileStream.Size to a variable and it will speed up. Stream.Size use three virtual function calls to find out the actual size

    ---
    What is slow is the fact of calling the Windows file API, not using virtual methods. Implement a cache is the solution. – Arnaud Bouchez Aug 15 '13 at 7:43

    @ArnaudBouchez, Size is not simple virtual method. It calls kernel32.FileSeek 3 times! Add Position (which also calls FileSeek) - and you get 4 kernel calls in just one code line. That's four time greater than kernel calls inside Read/Write. – Alex May 25 '15 at 2:20

    @Alex Indeed. This was exactly my point - please read again my comment. And this is why I proposed to cache the size, and even more compute the current position within the loop when writing the content. Avoiding as much API calls as possible is always a good idea! – Arnaud Bouchez
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  10. #10
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 859
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 859
    Points : 11 303
    Points
    11 303
    Billets dans le blog
    6
    Par défaut
    La chose ennuyeuse qu'on découvre maintenant, c'est la suite, qui ne nous prémunit pas d'une erreur de lecture :

    Car si on lit 0 bytes là-dedans, on n'incrémentera pas le TotalBytesRead et donc on ne sortira pas (sauf si l'erreur de lecture est suffisamment violente, mais ceci est une autre histoire).
    C'est pire en cas d'erreur de lecture renvoyant -1...
    Delphi 5 Pro - Delphi 11.3 Alexandria Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  11. #11
    Expert confirmé
    Avatar de BeanzMaster
    Homme Profil pro
    Amateur Passionné
    Inscrit en
    Septembre 2015
    Messages
    1 899
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Amateur Passionné
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Septembre 2015
    Messages : 1 899
    Points : 4 346
    Points
    4 346
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Jipété Voir le message
    MP pour Jérome :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    //  if Not HasError then // test inutile, HasError EST déjà à False
          if TotalBytesRead <> FileStream.Size then HasError := True;
    Non non et ca c'est quoi

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    // Do something with Buffer data
            if Buffer[0]<>'A' then 
            begin
              HasError := True;
              Break;
            end;
    • "L'Homme devrait mettre autant d'ardeur à simplifier sa vie qu'il met à la compliquer" - Henri Bergson
    • "Bien des livres auraient été plus clairs s'ils n'avaient pas voulu être si clairs" - Emmanuel Kant
    • "La simplicité est la sophistication suprême" - Léonard De Vinci
    • "Ce qui est facile à comprendre ou à faire pour toi, ne l'est pas forcément pour l'autre." - Mon pèrei

    Mes projets sur Github - Blog - Site DVP

  12. #12
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 700
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 700
    Points : 13 138
    Points
    13 138
    Par défaut
    Une exception sera générée s'il devait y avoir un problème (mais ce sera principalement à la création du stream).

    Quant à l'optimisation sur la taille, je dirais oui si le fichier est ouvert en exclusif, ou au minimum en DenyWrite. Sinon rien ne dit qu'il n'y aura pas d'écriture après son ouverture et recalculer la taille pourrait être intéressant.
    (exemple : on pourrait très bien lire un fichier log en boucle sans libérer le handle)

    Citation Envoyé par Jipété Voir le message
    et le moyen que j'avais trouvé, tout en conservant l'idée de base, c'est de juste modifier le test en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        while TotalBytesRead < FileStream.Size do
    Et c'est correct
    La seule chose qui ne doit pas être omise dans ce cas-là est FileStream.Position := 0.

  13. #13
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 732
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 732
    Points : 15 137
    Points
    15 137
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    Citation Envoyé par Jipété;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        while TotalBytesRead < FileStream.Size do
    Et c'est correct


    Citation Envoyé par Andnotor Voir le message
    La seule chose qui ne doit pas être omise dans ce cas-là est FileStream.Position := 0.
    Alors ça c'est curieux, j'ai même testé, pour voir (en me disant que juste après un Create, Position ne pouvait qu'être à 0) et effectivement ça donne ça :
    Nom : showmess_filestream_position.png
Affichages : 157
Taille : 12,0 Ko

    Pourquoi cette précaution, alors ? Il pourrait en être autrement ?

    Citation Envoyé par BeanzMaster Voir le message
    Non non et ca c'est quoi

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    // Do something with Buffer data
            if Buffer[0]<>'A' then 
            begin
              HasError := True;
              Break;
            end;
    Mea culpa, mea maxima culpa : cette chose me gênait au milieu de la lecture du fichier, je l'ai virée puis oubliée,
    À ma décharge, je dirais que je ne voulais pas mélanger la récupération des données du fichier et leur traitement si lecture ok.

    Citation Envoyé par tourlourou Voir le message
    C'est pire en cas d'erreur de lecture renvoyant -1...
    Ah ben vi, si tu remets une pièce dans le juke-box, on va jamais voir le bout du tunnel,

    Je rappelle que je voulais juste corriger la faute dans l'exemple, pas le récrire de fond en comble,

    Bref, du coup j'ai pondu ça, et ça se passe en deux temps (sinon c'est infâme et tout embrouillé) -- ah, j'ai renommé HasError en ReadError :
    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
    22
    23
        fss := FileStream.Size;  // speed-up
        while TotalBytesRead < fss do
        begin
          BytesRead := FileStream.Read(Buffer, sizeof(Buffer)); // Read in sizeof(Buffer) bytes of data
          case BytesRead of
            -1: Break; // erreur fatale
            0 : begin  // erreur de lecture ?
                  ReadError := (TotalBytesRead <> FileStream.Size);
                  Break;
                end;
            else inc(TotalBytesRead, BytesRead);   // Increase TotalBytesRead by the number of bytes read
          end; // case
        end; // while
      finally
        FileStream.Free;
      end; // try
     
      case BytesRead of
        -1: ShowMessage('ERREUR FATALE');
        0 : if ReadError then ShowMessage('ERREUR DE LECTURE');
        else  // Do something with Buffer data
          ShowMessage(IntToStr(TotalBytesRead)); // 146 ou 3578
      end;
    J'ai testé en forçant BytesRead avant le 1er case et, ma foi, ça le fait.

    Alors, puisque Andnotor confirme ma justesse de vue à propos du test, retour au post no 1 et si quelqu'un a un compte pour poster sur leur wiki, page "Discussion", faudrait leur coller ça :
    +++
    Wrong test in last example of Generic files of any type (starting with "With larger files of many Gb, ...")

    Hello,
    The test
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      while TotalBytesRead <= FileStream.Size do  // While the amount of data read is less than or equal to the size of the stream do
    never terminates... Should be
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      while TotalBytesRead < FileStream.Size do  // While the amount of data read is less than to the size of the stream do
    Best regards,
    +++
    Merci à celui qui s'y colle.
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

Discussions similaires

  1. multi-upload dans un wiki
    Par ravens1988 dans le forum Langage
    Réponses: 1
    Dernier message: 23/11/2008, 22h39
  2. [MediaWiki] Comment personnaliser cette barre à outils dans le WIKI ?
    Par nadia lydia dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 1
    Dernier message: 07/07/2008, 23h28
  3. [MediaWiki] Package Wiki pour intranet HTTPS
    Par thierryyyyyyy dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 8
    Dernier message: 27/01/2008, 03h19
  4. Inserer du code javascript dans un wiki
    Par c.betty dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 27/02/2007, 21h01
  5. Réponses: 6
    Dernier message: 30/03/2006, 23h45

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