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

Discussion :

Comment avoir l'information d'une fermeture de console ?

  1. #1
    Membre du Club
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2018
    Messages
    124
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2018
    Messages : 124
    Points : 55
    Points
    55
    Par défaut Comment avoir l'information d'une fermeture de console ?
    Bonjour à tous,

    j'ai créé un petit programme en "application QT console" (fenêtre MSDos). Dans mon programme, je suis dans une boucle infinie, et je souhaiterai donner l'opportunité d'arrêter cette appli, mais avant de fermer, je souhaiterai faire un ".fclose" sur mon fichier.
    Je vois deux possibilités :
    1 - soit en utilisant la croix de la console, mais là je n'ai pas d'information de la fermeture, donc je ne peux pas fermer mon fichier
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    int main(int argc, char *argv[])
    {
      QCoreApplication a(argc, argv);
    ....
     
        return a.exec();
    }
    2 - soit en tapant un caractère dans la console, mais le "std::cin >> charact;" bloque le programme tant que l'opérateur n'a rien saisit et donc bloque le programme au niveau de cette ligne.

    Donc comment faire ?

    Merci d'avance

  2. #2
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 438
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 438
    Points : 43 081
    Points
    43 081
    Par défaut
    J'ai fait un tout petit peu de Qt donc je ne suis pas du tout un pro, et je ne programme pas vraiment.

    Mais ce que je peux t'en dire, c'est qu'il te faut utiliser les objet Qt et éviter les fonction purement C/C++ tels que cin, cout, fclose.

    T'es tu déjà documenté sur Qt ou tu pars de 0 ?

    Il te faut créer une boucle événementielle, mais je pense que QCoreApplication en fait une (à confirmer).

    Il te faut ensuite comprendre le système de SIGNAL/SLOT en gros tu lie un signal : un évènement comme l'appui d'une touche clavier par exemple à un SLOT : fonction à exécuter à la réception du SIGNAL.

    Pour le reste, je passe le relais aux pros de Qt.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 29
    Points : 113
    Points
    113
    Par défaut
    En dehors de QT, tu peux utiliser std::signal qui permet d'affecter une fonction pour gérer les signaux envoyés à l'application. Après, le signal que tu reçois est dépendant du système...

    Après, peut être que QT implémente ses propres fonctions de gestions.

  4. #4
    Membre du Club
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2018
    Messages
    124
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2018
    Messages : 124
    Points : 55
    Points
    55
    Par défaut
    Merci pour vos réponses, alors dans l'ordre je viens du monde du C, et le C++ est déjà un peu obscure pour moins, alors ne parlons pas de celui de Qt
    Sinon, où puis trouver un document simple et très bien expliqué sur la gestion du système signal/slot ?
    Voire même des petits exemples simples de programme déjà tout fait ?
    Merci

  5. #5
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par DarkinGoD Voir le message
    En dehors de QT, tu peux utiliser std::signal qui permet d'affecter une fonction pour gérer les signaux envoyés à l'application. Après, le signal que tu reçois est dépendant du système...

    Après, peut être que QT implémente ses propres fonctions de gestions.
    Surtout pas, malheureux!
    std::signal permet de définir une fonction qui sera appelée au cas où un signal de base émis par le système d'exploitation (tel que SIGINT) serait émis. Cela n'a rien à voir avec le problème!

    @Amfrey95 : le fait est que tu ne devrais pas garder un fichier ouvert en permanence le temps que ton application fonctionne : tu l'ouvres quand tu en as besoin, du lis ou tu écris dedans, et tu le referme. Et, si possible, tu fais les choses de manière à pouvoir limiter au maximum le nombre de fois où tu devras ouvrir le fichier.

    Si bien que, dans l'idéal, l'ordre logique pour travailler est:

    1- au début de l'application:

    Tu ouvres ton fichier, tu en extrait l'intégralité des informations qu'il contient et tu les représente sous une forme cohérente en mémoire

    2- durant l'exécution de l'application :

    tu ne travaille que sur les informations dont tu disposes en mémoire : ce sont ces informations que tu manipule / modifie / ajoute ou supprimes.

    tu n'as -- a priori -- absolument aucune raison d'accéder une nouvelle fois à un fichier qui a déjà été chargé

    3- à la fin de ton application :

    Tu veilles -- si nécessaire -- à reporter les modifications apportées aux informations dans le fichier.

    Cela revient le plus souvent à ... réécrire l'intégralité du fichier qui permet la persistance des données

    A moins bien sur que tu n'aies absolument pas modifié les données d'origine, et que tu te sois "contenté" d'en ajouter de nouvelles. Dans ce cas tout particulier, tu pourras peut-être (en fonction du format du fichier utilisé) envisager de te limiter à ... écrire les nouvelles données à la suite des précédentes

    Dans certains cas (lorsque les données en question correspondent à ce que l'on peut appeler un "niveau" dans l'application), il se peut que la logique de lecture / utilisation / sauvegarde s'effectue en boucle, voire que l'utilisateur puisse à n'importe quel moment décider de sauvegarder les modifications qu'il vient d'apporter.

    Mais la logique reste malgré tout la même :
    • S'il faut lire des informations dans un fichier, on veille à le faire en une seule fois, pour pouvoir refermer le fichier "aussi vite que possible"
    • S'il faut manipuler des informations, il ne faut pas devoir aller les chercher dans un fichier
    • S'il faut sauvegarder des informations, on veille à le faire en une seule fois, pour pouvoir refermer le fichier "aussi vite que possible".


    En travaillant de la sorte, il n'y aura plus aucun problème : ton fichier sera forcément fermé après la lecture de ton fichier.

    Par exemple, ton application pourrait utiliser une fonction readFile proche de
    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
    /* je ne sais absolument pas quel genre de données constitue ton fichier.
     * par facilité, on va considérer que ce sont des chaines de caractères, et que chaque
     * chaine de caractère correspond à une ligne dans le fichier
     *
     * La lecture renverra donc un tableau de chaines de caractères
     */
    std::vector<std::string> readFile(std::string const & filename){
        /* ouverture du fichier
         */
       std::ifstream ifs(filename);
       /* si cela n'a pas fonctionné */
        if(! ifs){
            /* impossible d'aller plus loin */
            std::string error("unable to open ");
            error.append(filename);
            throw std::runtime_error(error);
        }
        /* si on arrive ici, le fichier a pu être ouvert, on peut donc en extraire
         * le contenu.
         *
         * Nous avons besoin d'un tableau qui contiendra toutes les chaines de caractères
         * et d'une chaine de caractères "temporaire" pour l'extraction
         */
        std::vector<std::string> tab;
        std::string temp;
        /* tant qu'il est possible d'extraire une ligne dans le fichier */
        while(std::getline(ifs, temp){
            /* on ajoute la ligne dans le tableau */
            tab.push_back(temp);
        }
        /* arrivé ici, tab contient toutes les lignes du fichier, nous pouvons le renvoyer
        * à la fonction appelante
        */
        return tab;
    } // fichier sera automatiquement fermé en passant ici
    Au niveau de ta fonction principale, la lecture du fichier se fera avant d'entrer dans ta "boucle infinie", sous une forme proche de
    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
    int main(){
         auto strings = readfile("fichier.txt"); // C++11 inside : le compilateur sais que strings est un std::vector<std::string> 
         bool again{true}; // pour savoir s'il faut retourner dans la boucle 
         while(again){
            /* tu utilises à ton aise les chaines de caractères contenues dans strings
             * tu modifies again pour lui donner la valeur false lorsque l'utilisateur veut quitter
             * 
             * Cela implique -- bien sur -- que tu lui laisses le choix d'une manière ou d'une autre
             */
        }
        /* arrivé ici, l'utilisateur a voulu quitter, et l'application s'achève "naturellement"
         * en renvoyant une valeur de réussite au système d'exploitation
         */
        return 0;
    } // strings est correctement détruit ici, toute la mémoire qu'il utilisait est libérée
    J'ai ajouté un maximum de commentaires pour te permettre de comprendre facilement le code que je fournis. Mais n'hésites pas à poser des questions en cas de besoin
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 29
    Points : 113
    Points
    113
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Surtout pas, malheureux!
    std::signal permet de définir une fonction qui sera appelée au cas où un signal de base émis par le système d'exploitation (tel que SIGINT) serait émis. Cela n'a rien à voir avec le problème!
    A ma connaissance, un SIGBREAK est émis dans une application console et la question était bien :
    Citation Envoyé par Amfrey95
    Dans mon programme, je suis dans une boucle infinie, et je souhaiterai donner l'opportunité d'arrêter cette appli, mais avant de fermer, je souhaiterai faire un ".fclose" sur mon fichier.
    Après, je suis d'accord avec toi sur le fait de ne pas conserver un descripteur de fichier ouvert tout au long de l'exécution du programme, mais il a peut être une bonne raison de le faire... on manque juste d'info sur le sujet.

  7. #7
    Membre du Club
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2018
    Messages
    124
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2018
    Messages : 124
    Points : 55
    Points
    55
    Par défaut
    Effectivement j'ai une bonne raison de la faire, le soft reçoit en permanence des données qui proviennent d'une ligne série, et ces données sont enregistrées dans le fichier, donc faire une ouverture fermeture à chaque fois me ferait perdre du temps CPU, mais aussi augmenterait l'accès au disque dur.

  8. #8
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par DarkinGoD Voir le message
    A ma connaissance, un SIGBREAK est émis dans une application console
    Même SIGBREAK n'a aucune raison de provoquer un retour quelconque à l'application... Cela implique de la gestion d'erreur

    Or, s'il s'agit de fermer un fichier ouvert par l'application, ce n'est pas de la gestion d'erreur, mais bel et bien une action "normale" qui doit être exécutée lors du déroulement correct de l'application
    Citation Envoyé par Amfrey95 Voir le message
    Effectivement j'ai une bonne raison de la faire,
    Non, tu n' as aucune raison de le faire
    Citation Envoyé par Amfrey95 Voir le message
    le soft reçoit en permanence des données qui proviennent d'une ligne série, et ces données sont enregistrées dans le fichier, donc faire une ouverture fermeture à chaque fois me ferait perdre du temps CPU, mais aussi augmenterait l'accès au disque dur.
    Dans ce cas, met en place une structure RAII qui permettra de t'asurrer que le fichier associé au flux des données de sauvegarde sera correctement fermé lorsque l'application sera quittée.

    Une simple structure proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    struct Logger{
        Logger(std::string const & filename):ofs{filnemae}{
        }
        std::ofstream ofs;
    };
    peut parfaitement faire l'affaire en étant utilisée sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int main(){
        Logger log;
        bool again{true};
        while(again){
            /* récupérer les données "data" */
           log.ofs>>data>>"\n";
       }
       return 0;
    }
    qui permettra de s'assurer de la destruction de log lorsque l'on quitte l'application, et, de ce fait, d'assurer la fermeture correcte du fichier.

    (bien que, dans l'idéal, il serait utile de considérer la structure Logger comme étant un fournisseur de services)

    Mais std::signal permet, comme le dit si bien la documentation de définir un error handler. C'est à dire une toute dernière action à entreprendre lorsqu'une erreur survient et provoque la fermeture inopinée de l'application.

    Or, bien que ce ne soit pas l'idéal, même si tu décide de mettre fin à l'application au travers de <ctrl>+<C>, ce n'est pas une erreur, c'est partie intégrante du comportement normal de ton application : aucune boucle n'étant réellement "infinie" par nature.

    Je ne dis pas que cela ne peut pas fonctionner, d'ailleurs, ce n'est pas vrai, mais je dis que ce n'est pas fait pour. C'est comme si tu essayais d'enfoncer une vis avec un marteau: Il y a (parfois) moyen d'y arriver, mais le marteau n'est pas prévu pour cet usage. Et donc, même si elle fonctionne, ce n'est pas la solution que tu recherche!

    Dans l'idéal, le fichier serait normalement et correctement fermé après chaque écriture. Mais je comprend parfaitement que le fait d'ouvrir le fichier à chaque fois qu'il faut y ajouter une information et le refermer à chaque fois que l'écriture a été effectuée pourrait -- effectivement -- poser des problèmes à cause de la cadance à laquelle les données arrivent de ton port série, et que cette solution n'est donc pas envisageable.

    C'est la raison pour laquelle la seule solution passe par une structure RAII.
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

Discussions similaires

  1. Comment avoir des informations sur une table ?
    Par Shogun dans le forum Oracle
    Réponses: 2
    Dernier message: 09/01/2007, 15h40
  2. Réponses: 2
    Dernier message: 29/08/2006, 16h27
  3. comment transférer les information d'une bdd a un document word
    Par Hamza dans le forum Bases de données
    Réponses: 3
    Dernier message: 24/05/2006, 19h46
  4. Réponses: 3
    Dernier message: 10/03/2006, 14h15
  5. Comment avoir des information sur une BD?…
    Par kikimnet dans le forum Bases de données
    Réponses: 1
    Dernier message: 12/02/2005, 09h20

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