IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++Builder Discussion :

TFileOpen qui fait planter chemins d'accès (ca a évolué...)


Sujet :

C++Builder

  1. #1
    Membre chevronné Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    1 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 935
    Points : 2 014
    Points
    2 014
    Par défaut TFileOpen qui fait planter chemins d'accès (ca a évolué...)
    Bonjour,

    J'ai ces deux codes de création de fichier qui fonctionnent très bien dans mon programme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    if (TemoinOperationRealisee == true )
            {
            Memo_Status->Lines->Add("");
            Memo_Status->Lines->Add("Logiciel acquisition Fermé  " + FormatDateTime(" dddd dd mmm yyyy  ", Now()) + " à " +FormatDateTime("hh", Now()) +" h "+ FormatDateTime("nn", Now()) +" min "+ FormatDateTime("ss", Now()) +" s ") ;
            //enregistrement fichier .log de la session
            AnsiString NomFichierLog = "ARCHIVES\\";
            NomFichierLog = NomFichierLog + FormatDateTime("yyyy-mm-dd-hh", Now()) + "h" + FormatDateTime("nn", Now()) + "min" +  FormatDateTime("ss", Now()) + "s" + ".log";
            Memo_Status->Lines->SaveToFile(NomFichierLog);
            }
    else
            {
            }
    dans l'evenement FormClose pour sauver un fichier log
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    NomFichier = ".\\ARCHIVES\\";
    NomFichier = NomFichier + FormatDateTime("yyyy-mm-dd-hh", Now()) + "h" + FormatDateTime("nn", Now()) + "min" +  FormatDateTime("ss", Now()) + "s" + ".mash";
    FILE *fichier;
    unsigned long int k;
    fichier = fopen( NomFichier.c_str(), "w+");
    for (k = 0 ; k < NbARecevoir ; k=k+1)
            {
            fprintf(fichier, "%c", Donnees[k] );
            }
    fclose(fichier);
    Ces deux codes fonctionnent tres bien au moment où je les appelle, SAUF SI j'ai cliqué avant sur un bouton qui fait appel à une action standard TFIleOpen d'une ActionList. Ca plante alors quand je lance l'un ou l'autre des deux codes.
    Concernant cette action standard, voici ce que j'ai créé :
    création d'une ActionList
    Ajout d'une action standard TFileOpen
    Reglage du filtre pour l'ouverture de fichier
    Affectation du nom de cette action à la propriété Action du bouton
    ...rien de plus

    Je suppose qu'en lancant cette action, je charge un flux quelquepart qui fait planter ensuite mon logiciel mais, je ne vous ni quoi ni pourquoi.

    L'erreur annoncée par BCB est respectivment "EFCreatorError" et "EAccesViolation" pour les deux codes ci_dessus. (meme pas pareil dans les deux cas... )

    merci d'avance
    Il y a 10 sortes de personnes dans le monde : ceux qui comprennent le binaire et les autres

  2. #2
    Membre chevronné Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    1 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 935
    Points : 2 014
    Points
    2 014
    Par défaut
    Le bug est encore plus grave...

    Cela ne vient peut etre pas du TFileOpen mais plutot du reste du programme dans lesquel je l'ai créé (programme qui marche tres bien sans ca il faut quand meme le preciser...)

    En effet, un autre bug "EAccessViolation" apparait, quand je mets ce code dans le OnClick d'un bouton :

    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
    unsigned long int i;
    TMemoryStream *MS;
    unsigned long int Taille;
    char *Tableau;
    MS=new TMemoryStream();
    MS->LoadFromFile(".\\ARCHIVES\\mémoirepleine.mash");
    Taille=MS->Size;         //on récupère la taille du stream
    Tableau=new char[Taille];     // on instancie une zone égale à la taille du stream
     
    MS->Read(Tableau,Taille);    //on lit (remplit Tableau) tous les octets de la zone du stream délimitée par Taille
    for(i=0 ; i < Taille ; i++) Donnees[i] = Tableau[i] ;
    delete MS;     //on libère le flux
    delete[] Tableau; //on libere le Tableau de "Taille" cases
     
    unsigned char poidsFort = Donnees[8];
    unsigned char poidsFaible = Donnees[9];
    AnsiString NomINI ="";
    NomINI = NomINI + poidsFort + "-" + poidsFaible + ".ini" ;
    Label1->Caption = NomINI ;
    si je ne touche pas au bouton tout va bien je peux executer n'importe quel code du logiciel.
    si je clique sur le bouton, le code ci dessus s'execute sans problème et apres si le curseur de la souris passe sur n'importe quel autre composant de la form (passe sur un bouton, atteind un Memo ou autre), ca plante avec un message d'erreur "EAccessViolation !

    Je ne vois vraiment pas ce que le code ci dessus peut poser comme problème ! Surtout que je l'ai mis au point dans un autre projet, avec juste deux boutons et quelques Labels et il n'y a pas le moindre probleme ! J'y manipule des fichier texte dans tous les sens sans bug.

    Ce code seul ne pose pas de problème, le programme dans lesquel je l'insert ne pose pas problème et quand je mets les deux ensemble ca fait des étincelles...

    J'espère que ce troisième exemple de code qui pose problème vous permettra de m'aider car je suis desespéré là...

    merci d'avance
    Il y a 10 sortes de personnes dans le monde : ceux qui comprennent le binaire et les autres

  3. #3
    Membre chevronné
    Avatar de Gilles Louïse
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    421
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2002
    Messages : 421
    Points : 1 911
    Points
    1 911
    Par défaut
    Dans le code que vous donnez, on ne voit pas la création par new de Donnees, il y a donc une violation d'accès parce que vous écrivez n'importe où en mémoire par l'instruction Donnees[i] = Tableau[i]. Pour corriger ce code il faut créer la chaîne de caractères Donnees par l'instrcution Donnees=new char[Taille] juste après la création de votre tableau.

    À bientôt
    Gilles

  4. #4
    Membre chevronné Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    1 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 935
    Points : 2 014
    Points
    2 014
    Par défaut
    aye ! pardon , j'avais oublié de préciser...

    Donnees est déclaré comme variable publique... Donc, a prioris ce n'est pas ca il me semble.
    j'ai bien un new char Donnees[....

    et le delete Donnees qui va avec dans l'évènement OnDestroy de ma form

    *********************************************************

    Par contre, je reviens pour cela, je viens de trouver comment corriger le bug décrit dans mon second message :

    J'avais le bug avec un tableau char donnees[] déclaré en publique avec une taille de 524290. et le bug apparaissait quand je lisait un fichier texte contenant 524287 caractères.
    Je me suis rendu compte ensuite que le bug disparaissait en ouvrant un fichier texte de seulement 321523 caractères alors j'ai déclaré un tableau char donnees[] plus grand.
    En déclarant une taille de 529000 ca marche.

    Je ne comprend pas pourquoi il faut déclarer un tableau de 529000 cases alors que j'accede seulement aux 524287 premières mais bon, ca marche....
    Note : je suis certain d'acceder uniquement 524287 cases car si je demande l'affichage de la variable Taille dans un Label juste avant de commencer la boucle
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for(i=0 ; i < Taille ; i++) Donnees[i] = Tableau[i] ;
    j'ai bien que 524287 dans Taille .

    Par contre, et malgrè tous mes efforts, je ne vois pas du tout ce qui se passe avec le problème décrit dans mon premier message !

    Pour résumer mon incomprehension, : je ne vois pas ce qui peut causer un probleme d'acces mémoire quand on lance une TFileOpen. On charge quelquechose quand on fait ca ?

    merci encore
    Il y a 10 sortes de personnes dans le monde : ceux qui comprennent le binaire et les autres

  5. #5
    Membre chevronné Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    1 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 935
    Points : 2 014
    Points
    2 014
    Par défaut
    Je viens de comprendre ce qui me faisait planter ! mais j'ai besoin d'aide quand même...

    Dans les codes que j'execute et qui plantent aprés avoir fait appel à TFileOpen (et pas sinon), il y a toujour des appels de fichier du type :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    fopen( ".\\FICHIERS\\essai.txt", "w+");
    avec un chemin relatif
    Suite à cette constatation, j'ai fait des essais et je me suis rendu compte que l'appel de TFileOpen change la position relative des fichiers

    Si je dois faire .\\FICHIERS\\essai.txt avant l'appel de TFileOpen, je dois faire ..\\FICHIERS\\essai.txt pour accéder le même fichier après avoir executé TFileOpen et ouvert un fichier placé dans un autre repertoire de la racine.

    : Y a t-il un moyen de contourner ce problème pour que les chemins d'acces restent toujours relatif à l'endroit où se trouve le .exe ?
    : A défaut, comment peut on savoir où on se trouve ? bref comment gère t-on ce phénomène normalement ?

    merci
    Il y a 10 sortes de personnes dans le monde : ceux qui comprennent le binaire et les autres

  6. #6
    Membre chevronné
    Avatar de Gilles Louïse
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    421
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2002
    Messages : 421
    Points : 1 911
    Points
    1 911
    Par défaut
    Je ne vois pas de lien entre TFileOpen et la nécessité d'utiliser des chemins relatifs car dans l'événement OnAccept de TFileOpen, le nom du fichier sélectionné à savoir FileOpen1->Dialog->FileName est donné avec le chemin complet. Donc l'événement OnAccept peut commencer comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void __fastcall TForm1::FileOpen1Accept(TObject *Sender)
    {
    AnsiString NomFic=FileOpen1->Dialog->FileName;
    }
    Le nom du fichier NomFic contient le chemin complet, libre à vous de l'utiliser comme vous voulez par la suite.

    À bientôt
    Gilles

  7. #7
    P50
    P50 est déconnecté
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 6
    Points : 6
    Points
    6
    Par défaut
    Bonjour,

    Il me semble que tu devrais écrire dans ton fopen le directory complet. Attention, tu dois mettre dans ton chemin d'accès aux données des / au lieu des \

    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    FILE* f;
    f=fopen(f,"C:/xxxx/Projet/donnees.txt","w");
    ça marche comme cela, me semble t'il!

  8. #8
    Membre chevronné Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    1 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 935
    Points : 2 014
    Points
    2 014
    Par défaut
    Bonjour

    J'ai besoin de mettre des chemins relatifs pour l'ecrire dans un fichier.
    Par exemple j'ai une partie de mon logiciel qui doit créer un fichier toujour dans le meme repertoire, sans rien demander à personne.

    J'ouvre un fichier avec TfileOpen et je crée ensuite un fichier ailleur, toujour le meme, toujour au meme endroit.

    de la meme manière, je doit à un moment aller lire un fichier ini lui aussi toujour dans le meme repertoire.

    Petiv's50 : Il me semble que ce sont bien des \ qu'il faut mettre...Ce sont meme \\ (2 x \)

    merci
    Il y a 10 sortes de personnes dans le monde : ceux qui comprennent le binaire et les autres

  9. #9
    Membre chevronné
    Avatar de Gilles Louïse
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    421
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2002
    Messages : 421
    Points : 1 911
    Points
    1 911
    Par défaut
    Je n'ai pas de réponse directe à ce dont vous parlez mais de toute façon, avec un outil surpuissant comme C++ Builder, on n'utilise plus du tout ces vieilles instructions C telles que fopen ou fclose et autres. Si vous avez un fichier texte à traiter, utilisez un TStringList avec LoadFromFile et SaveToFile (alinéa 44 de mes Remarques) ou un TMemoryStream ou bien d'autres composants visibles ou invisibles.

    À bientôt
    Gilles

  10. #10
    Membre chevronné Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    1 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 935
    Points : 2 014
    Points
    2 014
    Par défaut un peu plus concret...
    Voici deux exemples de cas où je bloque pour déterminer le nom du fichier.

    exemple 1 :
    a tout moment, je peux cliquer sur un bouton pour lire des données sur l'usb puis ces données sont ecrites dans un fichier "archive" portant la date de l'acquisition.

    J'utilise ce code pour créer le fichier (j'ai remplacé le fopen par quelquechose de plus puissant):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    AnsiString NomFichier = ".\\ARCHIVES\\";
    NomFichier = NomFichier + FormatDateTime("yyyy-mm-dd-hh", Now()) + "h" + FormatDateTime("nn", Now()) + "min" +  FormatDateTime("ss", Now()) + "s" + ".mash";
     
    TFileStream *FluxEcrit    ;
    FluxEcrit = new TFileStream(NomFichier,fmCreate) ;
    FluxEcrit->WriteBuffer(Donnees,NbARecevoir) ;
    delete FluxEcrit;     //on libère le flux
     
    //donnees est un tableau de char declaré en publique, NbArecevoir est une variable publique également
    ce fichier créé étant une archive, l'utilisateur n'a pas à choisir où il la met et ce sera toujours dans le répertoire ARCHIVES situé dans la racine où se trouve le .exe

    Si on ouvre un fichier dans un autre repertoire avec une TFileOpen avant l'execusion de ce code ca plante car le .\\ ne convient plus.

    : Comment peut on remplacer .\\ par le chemin qui mène au .exe ?

    exemple 2 :
    Ensuite, l'utilisateur peut ouvrir une des archives créé avec un TFileOpen et après cette ouverture, le logiciel reconnait 2 valeurs qui lui indiquent l'origine du fichier et lui permet d'aller chercher un fichier ini correspondant.

    [code]
    //à l'ouverture, on met le contenu de l'archive dans le tableau Donnees
    unsigned char poidsFort = Donnees[8];
    unsigned char poidsFaible = Donnees[9];
    AnsiString NomINI ="..\\cartes\\carte";
    NomINI = NomINI + poidsFort + "-" + poidsFaible + ".ini" ;
    TIniFile *Ini = new TIniFile(NomINI);
    //si poidsFort = 54 et poidsFaible = 37 , on va ouvrir le fichier ini "carte54-37.ini" qui se trouve dans le repertoire cartes situé dans le meme repertoire que le .exe

    : meme question, comment peut on remplacer .\\ par le chemin qui mène au .exe ?

    merci encore
    Il y a 10 sortes de personnes dans le monde : ceux qui comprennent le binaire et les autres

  11. #11
    Membre chevronné
    Avatar de Gilles Louïse
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    421
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2002
    Messages : 421
    Points : 1 911
    Points
    1 911
    Par défaut
    Je ne crois pas que vous puissiez jouer avec les répertoires relatifs, il faut savoir où se trouve votre exe avec la fonction getcwd (il faut ajouter #include "Dir.h" pour que ça marche) puis calculer votre relatif en absolu (i.e. indiquant clairement tout le chemin) de manière à éviter toute ambiguité. Vous pouvez par exemple faire ce calcul au moment de la construction de la classe princpale par exemple comme suit :

    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
    __fastcall TForm1::TForm1(TComponent* Owner)
       : TForm(Owner)
    {
    const int LongBuf=1000;
    AnsiString NomFic;
    char DirTrav[LongBuf];
    int i;
    bool ok;
     
    getcwd(DirTrav,LongBuf);
    NomFic=DirTrav;
    i=NomFic.Length();
    ok=true;
    while(ok) ok=(NomFic[i--]!='\\');
    NomFic=NomFic.SubString(1,i);
    NomFic+="\\ARCHIVES";
    }
    getcwd vous donne le répertoire où se trouve l'exe, on recule à partir de la fin jusqu'à trouver \\ et on ajoute ARCHIVES, ainsi NomFic contient le chemin réel bien que ce soit relatif. Il y a peut-être d'autres solutions plus simples mais je suis de la vieille école, je programme quasiment tout moi-même.

    À bientôt
    Gilles

  12. #12
    Membre habitué
    Inscrit en
    Mars 2002
    Messages
    105
    Détails du profil
    Informations forums :
    Inscription : Mars 2002
    Messages : 105
    Points : 133
    Points
    133
    Par défaut
    Bonjour,

    Comment peut on remplacer .\\ par le chemin qui mène au .exe ?
    On peut utiliser :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    ExtractFilePath(Application->ExeName);
    Nicolas

  13. #13
    Membre chevronné Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    1 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 935
    Points : 2 014
    Points
    2 014
    Par défaut
    Gilles, j'ai essayé votre code et c'est exactement ce que je cherchais.
    Pour le moment, je n'ai même pas besoin du
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    i=NomFic.Length(); 
    ok=true; 
    while(ok) ok=(NomFic[i--]!='\\'); 
    NomFic=NomFic.SubString(1,i);
    Nicolas, merci aussi, je vais regarder...

    merci
    Il y a 10 sortes de personnes dans le monde : ceux qui comprennent le binaire et les autres

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

Discussions similaires

  1. Réponses: 7
    Dernier message: 12/11/2006, 02h26
  2. [Access 2003] Macro qui fait planter Access
    Par nuriel2 dans le forum Access
    Réponses: 5
    Dernier message: 10/05/2006, 14h00
  3. Supprimer une crontab qui fait planter le server
    Par osmoze dans le forum Administration système
    Réponses: 5
    Dernier message: 31/03/2006, 15h42
  4. 56k qui fait planter le PC
    Par Spack dans le forum Périphériques
    Réponses: 4
    Dernier message: 03/10/2005, 19h35
  5. probleme de requette qui fait planter powergres
    Par fehmitn dans le forum PostgreSQL
    Réponses: 1
    Dernier message: 15/09/2004, 18h48

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