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 :

Le grand brouillard du IOresult [Lazarus]


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 Le grand brouillard du IOresult
    Bonjour,

    j'ai décidé de blinder une procédure toute simple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
      var  // http://wiki.freepascal.org/File
        MyFile: file;
        Data: array [0..53] of Byte; // taille BitmapFileHeader + BitmapInfoHeader v1
      begin
        AssignFile(MyFile, '/chemin/fichier');
        Reset(MyFile, 1 { size of read chunk });
        try
          BlockRead(MyFile, Data, SizeOf(Data));
        finally
          CloseFile(MyFile);
        end;
      end;
    Bien sûr il faut passer par IOresult et comm' d'hab' le web est plein d'infos, à tel point que je viens vous solliciter, les lecteurs de diskettes ayant maintenant disparu, ce qui est bien regrettable parce que pour faire des tests avec pas de diskette, diskette write-protect ou diskette full, c'était bien pratique.

    Ça devient compliqué, maintenant, surtout quand on lit, dans deux sujets du même forum, ce genre de choses (c'est moi qui mets en gras) :
    make sure you have called IOResult after your last file operation, but before the {$I+}
    always read out IOResult after doing an {$I+}.
    source 1re ligne -- source 2de ligne


    Pour ne pas prendre de risque, il faudrait donc écrire, en fin de procédure,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        //...
        Closefile(f);
        Error := IOResult; // make sure you have called IOResult after your last file operation, but before the {$I+} -- http://forum.lazarus.freepascal.org/index.php?topic=38751.msg264193#msg264193
        {$I+}
        Error := IOResult; // always read out IOResult after doing an {$I+}. -- http://forum.lazarus.freepascal.org/index.php/topic,26087.msg160078.html#msg160078
    et tester le Error à chaque fois.

    L'ennui c'est la règle trouvée dans le message indiqué juste au-dessus (So best practice is... keep your {$I-}/{$I+} as short as possible) qui en rajoute une couche parce que, partant de l'exemple donné dans ce post, je me demande si c'est comme ça qu'il faudrait faire :
    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
    29
    30
    31
    32
    33
    34
    35
    36
    var
      s : string;
      f : textfile;
      Error  : integer;
      procedure ManageError(E: integer);
      begin
        ShowMessage(IntToStr(E));
      end;
    begin
      s := inputbox('Saisie de texte','Entrer une ligne de texte :','blabla');
      if s <> '' then begin
        Error := IOResult; // use the IOResult before an IO-operation (to reset it). -- http://forum.lazarus.freepascal.org/index.php/topic,26087.msg160078.html#msg160078
        {$I-}
        AssignFile(f,'/chemin/test.txt');
        Error := IOResult; // make sure you have called IOResult after your last file operation, but before the {$I+} -- http://forum.lazarus.freepascal.org/index.php?topic=38751.msg264193#msg264193
        {$I+}
        if bool(Error) then begin ManageError(Error); exit; end;
        {$I-}
        Rewrite(f);
        Error := IOResult; // make sure you have called IOResult after your last file operation, but before the {$I+} -- http://forum.lazarus.freepascal.org/index.php?topic=38751.msg264193#msg264193
        {$I+}
        if bool(Error) then begin ManageError(Error); exit; end;
        {$I-}
        WriteLn(f,s);
        Error := IOResult; // make sure you have called IOResult after your last file operation, but before the {$I+} -- http://forum.lazarus.freepascal.org/index.php?topic=38751.msg264193#msg264193
        {$I+}
        if bool(Error) then begin ManageError(Error); exit; end;
        {$I-}
        Closefile(f);
        Error := IOResult; // make sure you have called IOResult after your last file operation, but before the {$I+} -- http://forum.lazarus.freepascal.org/index.php?topic=38751.msg264193#msg264193
        if bool(Error) then begin ManageError(Error); exit; end;
        {$I+}
        Error := IOResult; // always read out IOResult after doing an {$I+}. -- http://forum.lazarus.freepascal.org/index.php/topic,26087.msg160078.html#msg160078
        if bool(Error) then begin ManageError(Error); exit; end;
      end;
    end;
    Merci pour vos avis avisés,
    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
    Expert confirmé
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    3 422
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 422
    Points : 5 824
    Points
    5 824
    Par défaut
    salut

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    {$I+} default generates the EInOutError exception when an IO error occurs. 
     
    {$I-} does not generate an exception. Instead, it is the responsiblity of the program to check the IO operation by using the IOResult routine.
    donc si tu est en {$I-} masque tout simplement l’exception
    elle deviens donc muette mais ce n'est pas pour autant qu'elle n'existe pas

    c'est a toi de gérer les erreurs il n'y a pas d’exception bloquantes généré par le système

    pour ma part j'utiliserai des TFileStream et la gestion d'ecxeption mises en place par les compilateur
    Nous souhaitons la vérité et nous trouvons qu'incertitude. [...]
    Nous sommes incapables de ne pas souhaiter la vérité et le bonheur, et sommes incapables ni de certitude ni de bonheur.
    Blaise Pascal
    PS : n'oubliez pas le tag

  3. #3
    Expert éminent
    Avatar de jurassic pork
    Homme Profil pro
    Bidouilleur
    Inscrit en
    Décembre 2008
    Messages
    3 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bidouilleur
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2008
    Messages : 3 954
    Points : 9 284
    Points
    9 284
    Par défaut
    hello,
    Pour rejoindre ce que dit Anapurna concernant le TfileStream dans le message précédent, voici ce que dit le wiki FreePascal - File Handling In Pascal/fr :


    Style objet
    En plus des routines de manipulation de fichier vieux style, un nouveau système existe qui utilise le concept des flux (flux de données) à un niveau d'abstraction plus élevé, ce qui veut dire que vous en tant que programmeur avez moins de chose à faire pour traiter les fichiers.


    Fichiers binaires
    Pour l'ouverture des fichiers en accès direct, TFileStream devrait être utilisé. Cette classe est une encapsulation des procédures FileOpen, FileCreate, FileRead, FileWrite, FileSeek et FileClose qui se trouvent dans l'unité FileUtil.
    Voici un exemple d'utilisation pour lire un en-tête de fichier image bmp :
    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
    29
    30
    31
    32
    33
    34
    35
    procedure TForm1.Button3Click(Sender: TObject);
    const
      C_FNAME = 'M:\Temp\image.bmp';
    var
      BytesRead, x: integer;
      DataLine: string;
      inStream: TFileStream;
      Data: array [0..53] of byte; // taille BitmapFileHeader + BitmapInfoHeader v1
    begin
      instream := nil;
      try
        instream := TFilestream.Create(C_FNAME, fmOpenRead);
        BytesRead := instream.Read(Data, SizeOf(Data));
        if BytesRead = SizeOf(Data) then
        begin
          DataLine := '';
          for x := 0 to BytesRead - 1 do
          begin
            DataLine += intToHex(Data[x], 2) + ' ';
            if (((x + 1) mod 16) = 0 ) or (x = BytesRead - 1) then
            begin
              Memo1.Append(DataLine);
              DataLine := '';
            end;
          end;
        end
        else
          Memo1.Append('Erreur: BytesRead <> SizeOf(Data) :' + IntToStr(BytesRead));
      except
        on E: Exception do
          Memo1.Append('Erreur: ' + E.ClassName + #13#10 + E.Message);
      end;
      if instream <> nil then
        instream.Free;
    end;


    Il faut activer le contrôle d'Entrée/Sortie.
    Ami calmant, J.P
    Jurassic computer : Sinclair ZX81 - Zilog Z80A à 3,25 MHz - RAM 1 Ko - ROM 8 Ko

  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
    Ola !
    Citation Envoyé par anapurna Voir le message
    donc si tu est en {$I-} masque tout simplement l’exception
    elle deviens donc muette mais ce n'est pas pour autant qu'elle n'existe pas

    c'est a toi de gérer les erreurs il n'y a pas d’exception bloquantes généré par le système

    S'il n'y a pas de diskette, $I ou pas dans tous les cas tu te prends ça :
    Nom : no_disk.png
Affichages : 205
Taille : 7,7 Ko

    Par contre ta remarque est valide lors d'une tentative d'écriture sur une diskette pleine : pas d'erreur bloquante sauf si je le décide, et là, c'est une erreur bidon (101, "erreur de Write") un peu trop générique à mon goût alors que l'erreur système dit bien "Disk full Press OK to continue ou Abort to kill the prog".

    J'aurais bien aimé tester avec une vraie erreur hardware mais je ne vois pas trop comment gratter la piste magnétique d'un fichier représentant une diskette virtuelle,


    Citation Envoyé par jurassic pork Voir le message
    hello,
    Pour rejoindre ce que dit Anapurna concernant le TfileStream dans le message précédent, voici ce que dit le wiki FreePascal - File Handling In Pascal/fr :
    et voici ce qu'on trouve dans le lien à propos de l'optimisation des accès :

    Citation Envoyé par SO
    TFileStream is a loose wrapper around the Windows ReadFile() and WriteFile() API functions and for many use cases the only thing faster is a memory mapped file.
    However, there is one common scenario where TFileStream becomes a performance bottleneck. That is if you read or write small amounts of data with each call to the stream read or write functions. For example if you read an array of integers one item at a time then you incur a significant overhead by reading 4 bytes at a time in the calls to ReadFile().
    Alors oui, s'il est question de ne lire que les 54 premiers bytes d'un fichier, un TFileStream fera l'affaire, mais j'ai dans un coin de ma mémoire un vieux projet jamais abouti de travail sur les fichiers de machines virtuelles et là, ça se joue en dizaines de Gb !

    On en est là.
    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 confirmé
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    3 422
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 422
    Points : 5 824
    Points
    5 824
    Par défaut
    salut

    oui c'est normal ^^ ce n'est pas consideré comme un erreur entrée sortie mais comme une erreur critique pour pallier
    ce genre d'erreur il faut modifier le niveau de sécurité pour tester
    j'ai trouvé un truc qui peut t'aider sur swissdelphicenter :

    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
    function DiskInDrive(Drive: Char): Boolean;   // Disk can be a floppy, CD-ROM,...
    var
      ErrorMode: Word;
    begin
      ////// make it upper case //////
      if Drive in ['a'..'z'] then  
        Dec(Drive, $20); //Drive := UpperCase(Drive)
      ////// make sure it's a letter //////
      if not (Drive in ['A'..'Z']) then
        raise EConvertError.Create('Not a valid drive ID');
      ////// turn off critical errors //////
      ErrorMode := SetErrorMode(SEM_FailCriticalErrors);
      try
        ////// drive 1 = a, 2 = b, 3 = c, etc. //////
        if DiskSize(Ord(Drive) - $40) = -1 then
          Result := False
        else
          Result := True;
      finally
        ////// Restore old error mode //////
        SetErrorMode(ErrorMode);
      end;
    end;
    PS je viens de voir que la procédure est aussi dans la faq de developpez
    Nous souhaitons la vérité et nous trouvons qu'incertitude. [...]
    Nous sommes incapables de ne pas souhaiter la vérité et le bonheur, et sommes incapables ni de certitude ni de bonheur.
    Blaise Pascal
    PS : n'oubliez pas le tag

  6. #6
    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
    Bonjour,

    merci pour cette piste, qui permet d'éviter la fenêtre bloquante que j'ai montrée, c'est déjà ça, même si plus personne n'a de lecteur de diskette

    En fait, l'idée était de tester le fonctionnement du couple $IOCHECKS OFF / IOresult pour voir ce qu'il était possible d'en tirer, au vu des informations un peu aléatoires du web, et pour ce faire, de générer des erreurs et d'en examiner les résultats : le plus simple était donc de jouer sur l'absence de diskette, car je ne vais pas casser un disque dur juste pour voir le retour du IOresult,

    J'ai trouvé une discussion intéressante là, qui montre les fonctions impactées par le switch $IOCHECKS ON/OFF, je vous invite à y jeter un œil, c'est vite lu (comme les biscuits, )

    Et un test rapide sur une page simple et bien expliquée, qui fonctionne sous XP comme sous Linux, j'y ai juste ajouté ça au tout début :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    begin
      // pour être sûr qu'il n'y a pas de reliquat d'une opération précédente
      error := IOResult; // use the IOResult before an IO-operation (to reset it). -- http://forum.lazarus.freepascal.org/index.php/topic,26087.msg160078.html#msg160078
    et ça, presque tout en bas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
      //...
      RmDir('TempDirectory');
      // ajout jpt
      error := IOResult; // make sure you have called IOResult after your last file operation, but before the {$I+} -- http://forum.lazarus.freepascal.org/index.php?topic=38751.msg264193#msg264193
      if error = 0
      then ShowMessage('TempDirectory removed OK')
      else ShowMessageFmt('Error %d removing TempDirectory',[error]);
    En toute logique, en agissant ainsi, je ne pense pas que cette remarque (telle qu'indiquée dans mon post d'origine) // always read out IOResult after doing an {$I+}. -- http://forum.lazarus.freepascal.org/index.php/topic,26087.msg160078.html#msg160078 soit justifiée, donc je la zappe, sauf si quelqu'un peut démontrer qu'il la faut.

    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

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

Discussions similaires

  1. Déterminer la Valeur la plus grande dans une table
    Par arnaud_verlaine dans le forum Langage SQL
    Réponses: 9
    Dernier message: 22/08/2014, 23h35
  2. Le grand mode d'emploi du forum, à lire si vous souhaitez tout savoir !
    Par Anomaly dans le forum Mode d'emploi & aide aux nouveaux
    Réponses: 2
    Dernier message: 03/06/2013, 17h36
  3. Qu'est ce qu'un grand projet ?
    Par Geronimo dans le forum Débats sur le développement - Le Best Of
    Réponses: 62
    Dernier message: 04/04/2013, 14h52
  4. Surface trop grande
    Par Black_Daimond dans le forum DirectX
    Réponses: 1
    Dernier message: 18/01/2003, 03h02
  5. Réponses: 3
    Dernier message: 16/12/2002, 16h12

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