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

[Améliorations] Programme de manipulations de fichier


Sujet :

C

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 36
    Points : 19
    Points
    19
    Par défaut [Améliorations] Programme de manipulations de fichier
    Bonjour,

    Je viens vous présenter un programme permettant à l'utilisateur de manipuler (basiquement) ses fichiers.

    Voici le code :

    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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    #define MAX_LEN 	1000 	/* Taille de chaîne maximale */
    #define BASE		10	/* Base décimale */
     
     
    #define FAIL		0	
    #define SUCCESS		1 	/* Constantes pour les retours de fonction */
     
    typedef struct File
    {
        FILE* ptr;
        char* path;
    } File;
     
    int menu(long*);
    void readFile(File*);
    void createFile(File*);
    void writeFile(File*);
     
    void clean(void);
    int read_string(char*, const int);
    long read_long(long**);
    void error(void);
     
    int main(void)
    {
    	long ret, retMenu;		
    	File my_file;
     
    	my_file.ptr = NULL;
    	my_file.path = NULL;
     
    	printf("\n\n          zReader - Manipulez vos fichiers");
     
    	do
    	{
    		if((ret = menu(&retMenu)) == FAIL) 
    			error();
     
    		if(retMenu == 1) 
    			readFile(&my_file);
     
    		else if(retMenu == 2) 
    			createFile(&my_file);
     
    		else if(retMenu == 3) 
    			writeFile(&my_file);
     
    		else if(retMenu == 4) 
    			break;
     
    		else 
    			printf("\n Mauvaise saisie, recommencez !\n\n");
     
    	} while(1);
     
    	return EXIT_SUCCESS;
    }
     
    int menu(long* ret)
    {
    	printf( "\n\n\n   MENU\n"
    		" 1 - Lire un fichier\n"
    		" 2 - Créer un fichier\n"
    		" 3 - Ecrire dans un fichier\n"
    		" 4 - Quitter le programme\n\n"	
    		" Votre choix ? ");
    	if((read_long(&ret)) == FAIL)
    		return FAIL;
     
    	else
    		return SUCCESS;
    }
     
    void readFile(File* my_file)
    {
    	int retPath;
    	char str[MAX_LEN] = "";
     
    	my_file->path = malloc(MAX_LEN * sizeof(my_file->path));
     
    	while(1)
    	{	
    		printf("\n\n Entrez le chemin du fichier que vous souhaitez lire : ");
    		if((retPath = read_string(my_file->path, MAX_LEN)) == FAIL) 
    			error();
     
    		if((my_file->ptr = fopen(my_file->path, "r")) != NULL) 
    			break;
     
    		else 
    			printf("\n Mauvaise saisie : le fichier n'existe pas, recommencez !\n");
    	}
     
    	printf("\n Contenu du fichier : \n\n");
     
    	if(fgetc(my_file->ptr) != EOF) 	
    	{
    		fseek(my_file->ptr, 0, SEEK_SET);
     
    		while(fgets(str, MAX_LEN, my_file->ptr) != NULL) 
            		printf("%s", str);
    	}
     
    	else printf(" Désolé, le fichier est vide !");
     
    	fclose(my_file->ptr);
    	free(my_file->path);
    }
     
    void createFile(File* my_file)
    {
    	int retPath;
     
    	my_file->path = malloc(MAX_LEN * sizeof(my_file->path));
     
    	while(1)
    	{	
    		printf("\n\n Entrez le chemin du fichier que vous souhaitez créer : ");
    		if((retPath = read_string(my_file->path, MAX_LEN)) == FAIL) 
    			error();
     
    		if((my_file->ptr = fopen(my_file->path, "w")) != NULL) 
    			break;
     
    		else 	
    			printf("\n Mauvaise saisie : le chemin du fichier n'existe pas, recommencez !\n");
    	}
     
    	printf("\n Le fichier a bien été créé !");
     
    	fclose(my_file->ptr);
    	free(my_file->path);
    }
     
    void writeFile(File* my_file)
    {
    	int retPath, c;
    	char str[MAX_LEN * 5] = "";
     
    	my_file->path = malloc(MAX_LEN * sizeof(my_file->path));
     
    	while(1)
    	{	
    		printf("\n\n Entrez le chemin du fichier que vous souhaitez lire : ");
    		if((retPath = read_string(my_file->path, MAX_LEN)) == FAIL) 
    			error();
     
    		if((my_file->ptr = fopen(my_file->path, "w")) != NULL) 
    			break;
     
    		else 
    			printf("\n Mauvaise saisie : le fichier n'existe pas, recommencez !\n");
    	}
     
    	printf("\n Saisissez le texte à mettre dans le fichier (pour fermer, tapez \"close_file\") : \n\n");
     
    	while(c = read_string(str, sizeof(str)))
        	{
            	if(strstr(str, "close_file")) 
    			break;
     
            	fputs(str, my_file->ptr);
        	}
     
    	if(c == FAIL) 
    		error();
     
    	fclose(my_file->ptr);
    	free(my_file->path);
    }
     
    void clean(void)
    {
        	int c = 0;
        	while ((c = getchar()) != '\n' && c != EOF);
    }
     
    int read_string(char *str, const int length)
    {
        	char *ptr = NULL;
     
        	if(fgets(str, length, stdin) != NULL)
        	{
            	ptr = strchr(str, '\n');
     
            	if(ptr != NULL) 
    			*ptr = '\0';
     
            	else 
    			clean();
     
            	return SUCCESS;
        	}
     
        	else
        	{
            	clean();
     
            	return FAIL;
        	}
    }
     
    long read_long(long** ret)
    {
        	char str[MAX_LEN] = {0}; 
     
        	if(read_string(str, 100)) 
    	{
    		**ret = strtol(str, NULL, BASE);
    		return SUCCESS;
    	}
     
        	else 
    		return FAIL;
    }
     
     
    void error(void)
    {
    	fprintf(stderr, "Erreur fatale lors de la saisie");
    	exit(EXIT_FAILURE);
    }
    Comme vous pouvez le voir, le code est (hélas) assez loin d'être parfait, et j'aimerais avoir vos critiques et vos améliorations à propos de celui-ci.

    Merci d'avance,
    Lucas-84.

  2. #2
    Expert éminent sénior

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 603
    Détails du profil
    Informations personnelles :
    Âge : 66
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 603
    Points : 17 913
    Points
    17 913
    Billets dans le blog
    2
    Par défaut
    déjà une petite factorisation de la saisie d'un nom de fichier:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    	while(1)
    	{	
    		printf("\n\n Entrez le chemin du fichier que vous souhaitez lire : ");
    		if((retPath = read_string(my_file->path, MAX_LEN)) == FAIL) 
    			error();
     
    		if((my_file->ptr = fopen(my_file->path, "w")) != NULL) 
    			break;
     
    		else 
    			printf("\n Mauvaise saisie : le fichier n'existe pas, recommencez !\n");
    	}
    qui est 2 fois dans le code..
    "Un homme sage ne croit que la moitié de ce qu’il lit. Plus sage encore, il sait laquelle".

    Consultant indépendant.
    Architecture systèmes complexes. Programmation grosses applications critiques. Ergonomie.
    C, Fortran, XWindow/Motif, Java

    Je ne réponds pas aux MP techniques

  3. #3
    Membre actif Avatar de brachior
    Homme Profil pro
    Doctorant
    Inscrit en
    Mai 2011
    Messages
    190
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Doctorant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mai 2011
    Messages : 190
    Points : 293
    Points
    293
    Par défaut
    Pourquoi prendre en paramètre un double étoile ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    long read_long(long*);
    Ça suffit amplement ^^

    Par contre,
    Quel est l'intérêt de transmettre une structure si c'est pour l'allouer et la libérer dans la fonction ?
    C'est à se demander l'intérêt du pointeur dans la structure ^^

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    my_file->path = malloc(MAX_LEN * sizeof(my_file->path));
    /* [...] */
    free(my_file->path);
    De plus, si le tableau path à toujours la longueur constante du define MAX_LEN,
    Pourquoi ne pas laisser l'allocation statique ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    typedef struct File
    {
        FILE* ptr;
        char[MAX_LEN] path;
    } File;
    Ta fonction read_string remplace les retour chariot par des NULL.
    C'est pratique pour ta récupération de nombre, mais pour l'écriture dans un fichier,
    Ça veut dire qu'on ne peut pas revenir à la ligne =/

    Tes appels à error ne libèrent pas la mémoire.
    Bon certes, le programme quittant c'est l'OS qui se chargera de la libération ...
    Mais c'est bien parce que tes structures sont simples et qu'il est plutôt intelligent ...
    Parce que ne pas fermer un fichier, normalement c'est un coup à planter ce fichier ...

    Manque une fonction de libération de ta structure ^^

    Sinon, l'idée est sympa et fonctionne plutôt bien ^^
    Reste plus qu'à intégrer readline et les options en ligne de commandes

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 36
    Points : 19
    Points
    19
    Par défaut
    Merci beaucoup pour vos réponses !
    Je vais les prendre en compte, et je vous donne des nouvelles dès que cela est fait.

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 36
    Points : 19
    Points
    19
    Par défaut
    Voilà, j'ai corrigé quasiment toutes les erreurs indiquées.
    @souviron34, j'ai créé une nouvelle fonction :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void keyed_file(File* my_file, const char* mode)
    Elle permet la saisie d'un nom de fichier, et remplace ainsi les trois occurrences du code cité :

    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
    void keyed_file(File* my_file, const char* mode)
    {
    	int retPath;
     
    	while(1)
    	{	
    		printf("\n\n Entrez le chemin du fichier concerné : ");
    		if((retPath = read_string(my_file->path, MAX_LEN)) == FAIL) 
    			error();
     
    		if((my_file->ptr = fopen(my_file->path, mode)) != NULL) 
    			break;
     
    		else 
    			printf("\n Mauvaise saisie : le fichier n'existe pas, recommencez !\n");
    	}
    }
    Le deuxième paramètre mode est envoyé directement par les fonctions de manipulations de fichiers (create_file, write_file, read_file). Il permet de spécifier le mode d'ouverture du fichier concerné.

    @brachior, merci pour ce long message.
    La plupart des erreurs notées ont été corrigées.
    J'ai supprimé les allocations dynamiques grâce à l'idée de l'allocation statique.
    Pour la saisie dans les fichiers, j'ai utilisé directement la fonction fgets.
    A la suite de la remarque sur la fonction error, pleine de bon sens (), j'ai modifié en créant une fonction free_struct, avant de me rendre compte qu'à priori cette fonction était appelée avant l'ouverture des fichiers. Je demande tout de même une confirmation.

    En résumé, voici mon nouveau code :

    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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    #define MAX_LEN 	1000 	/* Taille de chaîne maximale */
    #define BASE		10	/* Base décimale */
     
     
    #define FAIL		0	
    #define SUCCESS		1 	/* Constantes pour les retours de fonction */
     
    typedef struct File
    {
        FILE* ptr;
        char path[MAX_LEN];
    } File;
     
    int menu(long*);
    void read_file(File*);
    void create_file(File*);
    void write_file(File*);
    void keyed_file(File*, const char*);
     
    void clean(void);
    int read_string(char*, const int);
    long read_long(long*);
    void error(void);
     
    int main(void)
    {
    	long ret, retMenu;		
    	File my_file;
     
    	printf("\n\n          zReader - Manipulez vos fichiers");
     
    	do
    	{
    		if((ret = menu(&retMenu)) == FAIL) 
    			error();
     
    		if(retMenu == 1) 
    			read_file(&my_file);
     
    		else if(retMenu == 2) 
    			create_file(&my_file);
     
    		else if(retMenu == 3) 
    			write_file(&my_file);
     
    		else if(retMenu == 4) 
    			break;
     
    		else 
    			printf("\n Mauvaise saisie, recommencez !\n\n");
     
    	} while(1);
     
    	return EXIT_SUCCESS;
    }
     
    int menu(long* ret)
    {
    	printf( "\n\n\n   MENU\n"
    		" 1 - Lire un fichier\n"
    		" 2 - Créer un fichier\n"
    		" 3 - Ecrire dans un fichier\n"
    		" 4 - Quitter le programme\n\n"	
    		" Votre choix ? ");
    	if((read_long(ret)) == FAIL)
    		return FAIL;
     
    	else
    		return SUCCESS;
    }
     
    void read_file(File* my_file)
    {
    	char str[MAX_LEN] = "";
     
    	keyed_file(my_file, "r");
     
    	printf("\n Contenu du fichier : \n\n");
     
    	if(fgetc(my_file->ptr) != EOF) 	
    	{
    		fseek(my_file->ptr, 0, SEEK_SET);
     
    		while(fgets(str, sizeof(str), my_file->ptr) != NULL) 
            		printf("%s", str);
    	}
     
    	else 
    		printf(" Désolé, le fichier est vide !");
     
    	fclose(my_file->ptr);
    }
     
    void create_file(File* my_file)
    {
    	keyed_file(my_file, "w");
     
    	printf("\n Le fichier a bien été créé !");
     
    	fclose(my_file->ptr);
    }
     
    void write_file(File* my_file)
    {
    	char str[MAX_LEN * 5] = "";
     
    	keyed_file(my_file, "w");
     
    	printf("\n Saisissez le texte à mettre dans le fichier (pour fermer, tapez \"close_file\") : \n\n");
     
    	while(fgets(str, sizeof(str), stdin) != NULL)
        	{
            	if (strstr(str,"close_file"))
                		break;
     
            	fputs(str, my_file->ptr);
        	}
     
    	fclose(my_file->ptr);
    }
     
    void keyed_file(File* my_file, const char* mode)
    {
    	int retPath;
     
    	while(1)
    	{	
    		printf("\n\n Entrez le chemin du fichier concerné : ");
    		if((retPath = read_string(my_file->path, MAX_LEN)) == FAIL) 
    			error();
     
    		if((my_file->ptr = fopen(my_file->path, mode)) != NULL) 
    			break;
     
    		else 
    			printf("\n Mauvaise saisie : le fichier n'existe pas, recommencez !\n");
    	}
    }
     
    void clean(void)
    {
        	int c = 0;
        	while ((c = getchar()) != '\n' && c != EOF);
    }
     
    int read_string(char *str, const int length)
    {
        	char *ptr = NULL;
     
        	if(fgets(str, length, stdin) != NULL)
        	{
            	ptr = strchr(str, '\n');
     
            	if(ptr != NULL) 
    			*ptr = '\0';
     
            	else 
    			clean();
     
            	return SUCCESS;
        	}
     
        	else
        	{
            	clean();
     
            	return FAIL;
        	}
    }
     
    long read_long(long* ret)
    {
        	char str[MAX_LEN] = {0}; 
     
        	if(read_string(str, 100)) 
    	{
    		*ret = strtol(str, NULL, BASE);
    		return SUCCESS;
    	}
     
        	else 
    		return FAIL;
    }
     
     
    void error(void)
    {
    	fprintf(stderr, "Erreur fatale lors de la saisie");
    	exit(EXIT_FAILURE);
    }
    Pour les options en ligne de commande et readline, je verrai un peu plus tard...

  6. #6
    Membre actif Avatar de brachior
    Homme Profil pro
    Doctorant
    Inscrit en
    Mai 2011
    Messages
    190
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Doctorant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mai 2011
    Messages : 190
    Points : 293
    Points
    293
    Par défaut
    En fait, je ne comprend pas l'intérêt de ta structure.
    Enfin, je ne comprends pas pourquoi les fonctions l'initialisent et la libèrent ...
    C'est pas leur rôle normalement Oo

    Enfin, peut être que je n'arrive pas a voir l'utilisation globale que tu veux en faire ^^
    Mais dans ton code actuel, je ne comprends pas trop =/

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 36
    Points : 19
    Points
    19
    Par défaut
    C'est-à-dire ? Il faut que je crée une seule variable my_file à chaque fonction ?

  8. #8
    Membre actif Avatar de brachior
    Homme Profil pro
    Doctorant
    Inscrit en
    Mai 2011
    Messages
    190
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Doctorant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mai 2011
    Messages : 190
    Points : 293
    Points
    293
    Par défaut
    En fait, tu stockes dans une structure un pointeur sur un fichier, ainsi que son path ...
    C'est très bien, mais dans tes fonctions,
    tu redemandes le path et tu ouvres et fermes ton fichier à chaque fois.

    Donc la question est :
    As tu besoin de ta structure à l'extérieur de tes fonctions ?
    A priori, non =/
    Car tes fonctions font à chaque fois l'initialisation et la libération.

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 36
    Points : 19
    Points
    19
    Par défaut
    (de retour de vacances)

    Ah, merci, je pense que j'ai compris.
    En gros, ma structure est inutile, et je crée directement les variables directement dans les fonctions ?

  10. #10
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 36
    Points : 19
    Points
    19
    Par défaut
    J'ai ajouté une fonctionnalité d'arguments en ligne de commande. Le code est un peu brouillon, mais a priori il est fonctionnel.

    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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
     
    #define MAX_LEN 	1000 	/* Taille de chaîne maximale */
    #define BASE		10	/* Base décimale */
     
    #define FAIL		0
    #define SUCCESS		1 	/* Constantes pour les retours de fonction */
     
    #define ARG         2
    #define NO_ARG      3 /* Constantes indiquant si l'utilisateur a utilisé les paramètres de main() ou pas */
     
     
    typedef struct File /* Structure du fichier */
    {
        FILE* ptr; /* Pointeur sur le fichier */
        char path[MAX_LEN]; /* Chaîne de caractères contenant le chemin du fichier */
    } File;
     
     
    void program(File*);
    int menu(long*);
    void read_file(File*, char*);
    void create_file(File*, char*);
    void write_file(File*, char*);
    void keyed_file(File*, const char*, char*);
     
    void clean(void);
    int read_string(char*, const int);
    long read_long(long*);
    void error(void);
    void fail_arg(void);
     
     
    int main(int argc, char *argv[])
    {
        File my_file;
     
        if(argc >= 2)
        {
            if(strcmp(argv[1], "read") == 0)
                read_file(&my_file, argv[2]);
     
            else if(strcmp(argv[1], "create") == 0)
                create_file(&my_file, argv[2]);
     
            else if(strcmp(argv[1], "write") == 0)
                write_file(&my_file, argv[2]);
     
            else
                fail_arg();
        }
     
        else
            program(&my_file);
     
        return EXIT_SUCCESS;
    }
     
    void program(File* my_file) /* Fonction principale du programme si l'utilisateur n'a pas passé d'argument */
    {
        long ret, retMenu;
     
        printf("\n\n          zReader - Manipulez vos fichiers");
     
        do
        {
            if((ret = menu(&retMenu)) == FAIL)
                error();
     
            switch(retMenu)
            {
                case 1:
                    read_file(my_file, NULL);
                    break;
     
                case 2:
                    create_file(my_file, NULL);
                    break;
     
                case 3:
                    write_file(my_file, NULL);
                    break;
     
                case 4:
                    break;
     
                default:
                    printf("\n Mauvaise saisie, recommencez !\n\n");
                    break;
            }
        }
        while(1);
    }
     
    int menu(long* ret) /* Affichage du menu */
    {
        printf( "\n\n\n   MENU\n"
                " 1 - Lire un fichier\n"
                " 2 - Créer un fichier\n"
                " 3 - Ecrire dans un fichier\n"
                " 4 - Quitter le programme\n\n"
                " Votre choix ? ");
        return (read_long(ret));
    }
     
    void read_file(File* my_file, char* arg) /* Lis un fichier */
    {
        char str[MAX_LEN] = "";
     
        keyed_file(my_file, "r", arg);
     
        printf("\n Contenu du fichier : \n\n");
     
        if(fgetc(my_file->ptr) != EOF)
        {
            fseek(my_file->ptr, 0, SEEK_SET);
     
            while(fgets(str, sizeof(str), my_file->ptr) != NULL)
                printf("%s", str);
        }
     
        else
            printf(" Désolé, le fichier est vide !");
     
        fclose(my_file->ptr);
    }
     
    void create_file(File* my_file, char* arg) /* Crée un fichier */
    {
        keyed_file(my_file, "w", arg);
     
        printf("\n Le fichier a été créé avec succès !");
     
        fclose(my_file->ptr);
    }
     
    void write_file(File* my_file, char* arg) /* Ecrit dans un fichier */
    {
        char str[MAX_LEN * 5] = "";
     
        keyed_file(my_file, "w", arg);
     
        printf("\n Saisissez le texte à mettre dans le fichier (pour fermer, tapez \"close_file\") : \n\n");
     
        while(fgets(str, sizeof(str), my_file->ptr) != NULL)
        {
            if(strstr(str, "close_file"))
                break;
     
            fputs(str, my_file->ptr);
        }
     
        fclose(my_file->ptr);
    }
     
    void keyed_file(File* my_file, const char* mode, char* arg) /* Permet la saisie et l'ouverture d'un fichier */
    {
        int retPath;
     
        if(arg != NULL)
        {
            if((my_file->ptr = fopen(arg, mode)) == NULL)
            {
                printf(" Le fichier est introuvable !\n");
                fail_arg();
                fclose(my_file->ptr);
                exit(EXIT_FAILURE);
            }
        }
     
        else
        {
            while(1)
            {
                printf("\n\n Entrez le chemin du fichier concerné : ");
                if((retPath = read_string(my_file->path, sizeof(my_file->path))) == FAIL)
                    error();
     
                if((my_file->ptr = fopen(my_file->path, mode)) != NULL)
                    break;
     
                else
                    printf("\n Mauvaise saisie : le fichier n'existe pas, recommencez !\n");
            }
        }
    }
     
    void clean(void) /* Nettoie le buffer */
    {
        int c = 0;
        while ((c = getchar()) != '\n' && c != EOF);
    }
     
    int read_string(char *str, const int length) /* Lis une chaîne de caractère */
    {
        char *ptr = NULL;
     
        if(fgets(str, length, stdin) != NULL)
        {
            ptr = strchr(str, '\n');
     
            if(ptr != NULL)
                *ptr = '\0';
     
            else
                clean();
     
            return SUCCESS;
        }
     
        else
        {
            clean();
     
            return FAIL;
        }
    }
     
    long read_long(long* ret) /* Lis un long */
    {
        char str[MAX_LEN] = {0};
     
        if(read_string(str, 100))
        {
            *ret = strtol(str, NULL, BASE);
            return SUCCESS;
        }
     
        else
            return FAIL;
    }
     
    void error(void) /* Si erreur lors de la saisie */
    {
        fprintf(stderr, "Erreur fatale lors de la saisie");
        exit(EXIT_FAILURE);
    }
     
    void fail_arg(void) /* Si l'utilisateur a rentré des arguments invalides */
    {
        printf(" Arguments invalides.\n Format : [mode][chemin du fichier]. \n mode = \"create\", \"write\" ou \"read\".");
    }

  11. #11
    Membre actif Avatar de brachior
    Homme Profil pro
    Doctorant
    Inscrit en
    Mai 2011
    Messages
    190
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Doctorant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mai 2011
    Messages : 190
    Points : 293
    Points
    293
    Par défaut
    Bonjour,

    Il y a toujours une chose qui me chagrine,
    Pourquoi read_file, create_file, write_file
    Font-elles ce que devrait faire des fonctions comme open_file et close_file ?

    Ce qui ferait que tu n'aurais plus à trimballer l'argument arg
    Qui d'ailleurs a un nom qui ne veut strictement rien dire Oo
    (à comprendre qu'il faut lire le code de la méthode pour comprendre son utilité)

    La méthode exit ne doit être utilisé que si le programme subit une erreur critique ... Et encore Oo
    Le problème de cette méthode, c'est qu'on ne sait pas vraiment quand est-ce qu'elle s'exécute,
    Le pourquoi et si elle a bien libérée toute la mémoire ...
    A préférer le retour d'un code d'erreur, en plus tes fonctions ne retournent rien donc aucune ambigüité en vue ^^

    Pour la ligne de commandes, tu peux aussi regarder du côté de getopt, une bibliothèque sensationnelle ^^

    Bonne continuation

  12. #12
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 36
    Points : 19
    Points
    19
    Par défaut
    Tout d'abord, merci pour ces réponses ; c'est très sympa de ta part de répondre à mes questions et à mes incertitudes de débutant.

    Pourquoi read_file, create_file, write_file
    Font-elles ce que devrait faire des fonctions comme open_file et close_file ?
    Au départ, parce que j'avais besoin de savoir en quel mode il fallait ouvrir le fichier. Du coup, il faudrait que j'écrive tout ça directement dans les cases du switch ?
    Ce qui m'embête un peu justement, avec arg (), c'est que, pour la saisie du fichier :
    - Si l'utilisateur a rentré des arguments en ligne de commande, on vérifie juste si le fichier existe (et on l'ouvre) ou pas (on affiche une erreur).
    - Si l'utilisateur n'a pas rentré des arguments en ligne de commande, on boucle jusqu'à ce qu'il ait rentré un fichier valide.
    Sauf erreur de ma part (et je suis sûr que c'est le cas ), je suis donc "obligé" de passer en paramètre un booléen indiquant si l'utilisateur avait rentré des arguments en ligne de commande, ce qui permet ainsi de faire mon code avec des conditions directement dans la fonction.

    La méthode exit ne doit être utilisé que si le programme subit une erreur critique ... Et encore Oo
    Le problème de cette méthode, c'est qu'on ne sait pas vraiment quand est-ce qu'elle s'exécute,
    Le pourquoi et si elle a bien libérée toute la mémoire ...
    A préférer le retour d'un code d'erreur, en plus tes fonctions ne retournent rien donc aucune ambigüité en vue ^^
    En effet, cette méthode me semble bien plus sûre et compréhensible, je vais essayer ça.

    Pour la ligne de commandes, tu peux aussi regarder du côté de getopt, une bibliothèque sensationnelle ^^
    Je ne connaissais pas, je vais voir ce que ça donne. Merci.

  13. #13
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 36
    Points : 19
    Points
    19
    Par défaut
    Je viens de regarder getopt, voilà mon nouveau main :

    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
    37
    38
    39
    40
    41
    42
    43
    int main(int argc, char *argv[])
    {
        File my_file;
        int c;
     
        c = getopt (argc, argv, "c:r:w:");
     
        if(c == EOF)
    	program(&my_file);
     
        else switch(c)
        {
    	case 'r':
    	    read_file(&my_file, optarg);
    	    break;
     
    	case 'c':
    	    create_file(&my_file, optarg);
    	    break;
     
    	case 'w':
    	    write_file(&my_file, optarg);
    	    break;
     
    	case '?':
    	    fail_arg();
    	    break;
        }
     
        if(optind < argc)
    	fail_arg();
     
        printf("\n");
     
        return EXIT_SUCCESS;
    }
     
    [...]
     
    void fail_arg(void) /* Si l'utilisateur a rentré des arguments invalides */
    {
        printf(" Arguments invalides.\n Format : -[mode][chemin du fichier]. \n mode = -c (créer), -w (écrire) ou -r (lire).");
    }

  14. #14
    Membre actif Avatar de brachior
    Homme Profil pro
    Doctorant
    Inscrit en
    Mai 2011
    Messages
    190
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Doctorant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mai 2011
    Messages : 190
    Points : 293
    Points
    293
    Par défaut
    Tu peux aussi imaginer une structure de code autre, plus espacée.
    Voila un exemple en pseudo-code :
    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
    37
    38
    39
    40
    41
    42
    43
    44
     
    main :
    	/* traite les options de la ligne de commande */
    	// ...
    	/* lance le traitement */
    	treat(filename, option)
     
    treat :
    	/* on récupère les informations */
    	si filename vide :
    		filename <- get_filename()
    	si option vide :
    		option <- get_option()
     
    	/* on traite la bonne ouverture et l'option */
    	si option est "lire" et open_file(filename, r) réussi :
    		retourne file_read(filename)
    	si option est "ecrire" et open_file(filename, w) réussi :
    		retourne file_write(filename)
    	si option est "créer" :
    		retourne file_create(filename)
     
    	/* en cas de problème on laisse le choix de redémarrer ou non */
    	si on veut veut recommencer :
    		retourne treat(null, option)
    	retourne "raté"
     
    get_filename :
    	/* récupère un nom de fichier */
     
    get_option :
    	/* récupère une option */
     
    open_file :
    	/* ouvre un fichier */
     
    read_file :
    	/* lit un fichier */
     
    write_file :
    	/* écrit dans un fichier */
     
    create_file :
    	/* crée un fichier */

  15. #15
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 36
    Points : 19
    Points
    19
    Par défaut
    En effet, ça semble beaucoup plus clair comme ça !
    (c'est toujours plus clair quand c'est pas moi qui le fait )
    Merci beaucoup, je vais essayer cette solution.

  16. #16
    Membre actif Avatar de brachior
    Homme Profil pro
    Doctorant
    Inscrit en
    Mai 2011
    Messages
    190
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Doctorant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mai 2011
    Messages : 190
    Points : 293
    Points
    293
    Par défaut
    Citation Envoyé par lucas-84 Voir le message
    c'est toujours plus clair quand c'est pas moi qui le fait
    C'est une question d'habitude et d'entrainement
    (et souvent suite à des circonstances douloureuses de maintient de code "pourri" xD)

    Tu remarqueras que dans mon pseudo-code,
    Je n'utilise pas ta structure,
    Tu peux la remettre si tu le souhaites ^^

  17. #17
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 36
    Points : 19
    Points
    19
    Par défaut
    Alors, voilà le nouveau code :

    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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <getopt.h> 
     
     
    #define MAX_LEN 	1000 	/* Taille de chaîne maximale */
     
    #define BASE		10	/* Base décimale */
     
    #define FAIL		0
    #define SUCCESS		1 	/* Constantes pour les retours de fonction */
     
     
    typedef struct File /* Structure du fichier */
    {
        FILE* ptr; /* Pointeur sur le fichier */
        char* path; /* Chaîne de caractères contenant le chemin du fichier */
    } File;
     
     
    int treat(File*, char*);
    int get_option(char* option);
    int get_filename(File* my_file);
    int read_file(File*);
    int create_file(File*);
    int write_file(File*);
    int open_file(File*, const char*);
    void close_file(File*);
    int again(File*, char*);
    int init(File*, char*);
    void end(File* my_file);
     
    void clean(void);
    int read_string(char*, const int);
    long read_long(long*);
    void fail_arg(void);
     
     
    int main(int argc, char *argv[])
    {
        int c, ret;
        char option;
     
        File my_file;
     
        if(init(&my_file, &option) == FAIL)
    	return EXIT_FAILURE;
     
        c = getopt(argc, argv, "c:r:w:");
     
        if(c != EOF)
        {
    	option = c;
    	strcpy(my_file.path, optarg);
        }
     
        ret = treat(&my_file, &option);
     
        end(&my_file);
     
        if(ret == FAIL)
    	return EXIT_FAILURE;
     
        return EXIT_SUCCESS;
    }
     
    int treat(File* my_file, char* option)
    {
        if(*option == ' ')
        {
    	if(get_option(option) == FAIL)
    	    return FAIL;
     
    	if(get_filename(my_file) == FAIL)
    	    return FAIL;
        }
     
        if(*option == 'r' && open_file(my_file, "r") == SUCCESS)
    	return read_file(my_file);
     
        if(*option == 'c' && open_file(my_file, "w") == SUCCESS)
    	return create_file(my_file);
     
        if(*option == 'w' && open_file(my_file, "w") == SUCCESS)
    	return write_file(my_file);
     
        else
        {
    	if(again(my_file, option) == FAIL)
    	    return FAIL;
     
    	return FAIL;
        }	
     
        return SUCCESS;    
    }
     
    int get_option(char* option)
    {
        long ret;
     
        printf("\n\n          zReader - Manipulez vos fichiers");
     
        do
        {
            printf( "\n\n\n   MENU\n"
                " 1 - Lire un fichier\n"
                " 2 - Créer un fichier\n"
                " 3 - Ecrire dans un fichier\n\n"
                " Votre choix ? ");
            if(read_long(&ret) == FAIL)
    	    return FAIL;
     
    	if(ret == 1)
    	    *option = 'r';
     
    	else if(ret == 2 || ret == 3)
    	    *option = 'w';
     
    	else 
    	    printf("\n Mauvaise saisie, recommencez !\n\n");
     
        } while(ret <= 0 || ret >= 4);
     
        return SUCCESS;    
    }
     
    int get_filename(File* my_file)
    {
        printf("\n Entrez le nom du fichier concerné : ");
     
        if(read_string(my_file->path, MAX_LEN) == FAIL)
    	 return FAIL;
     
        return SUCCESS;
    }
     
    int read_file(File* my_file) /* Lis un fichier */
    {
        char str[MAX_LEN] = "";
     
        printf("\n Contenu du fichier : \n\n");
     
        if(fgetc(my_file->ptr) != EOF)
        {
            fseek(my_file->ptr, 0, SEEK_SET);
     
            while(fgets(str, sizeof(str), my_file->ptr) != NULL)
                printf("%s", str);
        }
     
        else
            printf(" Désolé, le fichier est vide !\n");
     
        close_file(my_file);
     
        return SUCCESS;
    }
     
    int create_file(File* my_file) /* Crée un fichier */
    {
        printf("\n Le fichier a été créé avec succès !\n");
     
        close_file(my_file);
     
        return SUCCESS;
    }
     
    int write_file(File* my_file) /* Ecrit dans un fichier */
    {
        char str[MAX_LEN * 5] = "";
     
        printf("\n Saisissez le texte à mettre dans le fichier (pour fermer, tapez \"close_file\") : \n\n");
     
        while(fgets(str, sizeof(str), stdin) != NULL)
        { 
            if(strstr(str, "close_file"))
                break;
     
            fputs(str, my_file->ptr);
        } 
     
        close_file(my_file);
     
        return SUCCESS;
    }
     
    int open_file(File* my_file, const char* mode)
    {
        if((my_file->ptr = fopen(my_file->path, mode)) != NULL)
    	return SUCCESS;
     
        else
    	return FAIL;
    }
     
    void close_file(File* my_file)
    {
        fclose(my_file->ptr);
    }
     
    int again(File* my_file, char* option)
    {
        char c;
     
        printf(" Erreur. Recommencer ? (o/n) ");
        scanf(" %c", &c);
     
        if(c == 'o')
        {
    	if(init(my_file, option) == FAIL)
    		return FAIL;
     
    	return treat(my_file, option);
        }
     
        else
    	return SUCCESS;
    }
     
    int init(File* my_file, char* option)
    {
        if((my_file->path = malloc(sizeof(char) * MAX_LEN)) == NULL)
    	return FAIL;
     
        *option = ' ';
     
        return SUCCESS;
    }
     
    void end(File* my_file)
    {
        free(my_file->path);
    } 
     
    void clean(void) /* Nettoie le buffer */
    {
        int c = 0;
        while ((c = getchar()) != '\n' && c != EOF);
    }
     
    int read_string(char *str, const int length) /* Lis une chaîne de caractère */
    {
        char *ptr = NULL;
     
        if(fgets(str, length, stdin) != NULL)
        {
            ptr = strchr(str, '\n');
     
            if(ptr != NULL)
                *ptr = '\0';
     
            else
                clean();
     
            return SUCCESS;
        }
     
        else
        {
            clean();
     
            return FAIL;
        }
    }
     
    long read_long(long* ret) /* Lis un long */
    {
        char str[MAX_LEN] = {0};
     
        if(read_string(str, 100))
        {
            *ret = strtol(str, NULL, BASE);
            return SUCCESS;
        }
     
        else
            return FAIL;
    }
     
    void fail_arg(void) /* Si l'utilisateur a rentré des arguments invalides */
    {
        printf(" Arguments invalides.\n Format : -[mode][chemin du fichier]. \n mode = -c (créer), -w (écrire) ou -r (lire).");
    }

  18. #18
    Membre actif Avatar de brachior
    Homme Profil pro
    Doctorant
    Inscrit en
    Mai 2011
    Messages
    190
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Doctorant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mai 2011
    Messages : 190
    Points : 293
    Points
    293
    Par défaut
    Il y a une fuite

    Ta méthode again ne libère pas la structure avant d'en initialiser une autre.
    D'ailleurs, pourquoi allouer dynamiquement la variable path ?

    De plus, la fin de ta fonction treat pose problème,
    Si il y a une erreur, ça renverra toujours FAIL ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    int treat(File* my_file, char* option)
    {
        /* [...] */
        else
        {
            /* ici tu retournes toujours FAIL */
            if(again(my_file, option) == FAIL)
                return FAIL;
            return FAIL;
        }
        return SUCCESS;  
    }
    Et ta fonction again n'a pas besoin de réinitialiser quoi que ce soit :

    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
    int again(File* my_file, char* option)
    {
        char c;
        printf(" Erreur. Recommencer ? (o/n) ");
        scanf(" %c", &c);
        if(c == 'o')
        {
            if(init(my_file, option) == FAIL)
                return FAIL;
            /*
                Tu risque d'avoir un "stack overflow" ici
                C'est à dire que la pile d'appel va être surchargée
                Imagine le scénario que l'utilisateur se trompe
                de nom de fichier sans arret ...
            */
            return treat(my_file, option);
        }
        else
            return SUCCESS;
    }
    Tu peux remplacer tout ça par :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    int treat(File* my_file, char* option)
    {
    	/* [...] */
    	option = '';
    	return (again() == SUCCES) ? treat(my_file, option) : FAIL;
    }
     
    int again()
    {
        printf(" Erreur. Recommencer ? (o/n) ");
        return (fgetc(stdin) == 'o') ? SUCCESS : FAIL;
    }
    Ah, un truc sympa pour la lisibilité (enfin c'est mon avis ^^)
    C'est d'éviter de mettre un else si il est inutile,
    Par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    if(test)
        return 0;
    else
        return 1;
    équivaut à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    if(test)
        return 0;
    return 1;
    bon après y a plus illisible mais plus stylé :p
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    return (test) ? 0 : 1;
    Bon, si t'es chaud,
    Tu peux essayer de modifier ta condition d'arrêt d'écriture dans un fichier pour utiliser des signaux,
    Par exemple SIGINT (Ctrl + C) ^^

  19. #19
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 36
    Points : 19
    Points
    19
    Par défaut
    J'ai toujours eu du mal avec les ternaires, alors c'est vrai que je ne les utilise pas trop de moi-même, mais il faut avouer qu'ils ont l'avantage de bien raccourcir le code.
    Pour la fonction again(), le return en une seule ligne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return (fgetc(stdin) == 'o') ? SUCCESS : FAIL;
    était fort concis, mais il ne permettait pas de vider le buffer. Du coup, on se retrouvait avec des exécutions du genre :

    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
    $ ./a.out
     
     
              zReader - Manipulez vos fichiers
     
     
       MENU
     1 - Lire un fichier
     2 - Créer un fichier
     3 - Ecrire dans un fichier
     
     Votre choix ? 1
     
     Entrez le nom du fichier concerné : jfoidsjgoiqgoh
     Erreur. Recommencer ? (o/n) o
     Erreur. Recommencer ? (o/n) $
    J'ai donc refait la fonction sur beaucoup plus de lignes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int again(void)
    {
        int c;
     
        printf(" Erreur. Recommencer ? (o/n) ");
        c = fgetc(stdin);
        clean();
     
        return(c == 'o') ? SUCCESS : FAIL;
    }

  20. #20
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 36
    Points : 19
    Points
    19
    Par défaut
    Ah, au fait, le code en entier :

    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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <getopt.h> 
     
     
    #define MAX_LEN 	1000 	/* Taille de chaîne maximale */
     
    #define BASE		10	/* Base décimale */
     
    #define FAIL		0
    #define SUCCESS		1 	/* Constantes pour les retours de fonction */
     
     
    typedef struct File /* Structure du fichier */
    {
        FILE* ptr; /* Pointeur sur le fichier */
        char path[MAX_LEN]; /* Chaîne de caractères contenant le chemin du fichier */
    } File;
     
     
    int treat(File*, char*);
     
    int get_option(char* option);
    int get_filename(File* my_file);
     
    int read_file(File*);
    int create_file(File*);
    int write_file(File*);
     
    int open_file(File*, const char*);
    void close_file(File*);
     
    int again(void);
    void fail_arg(void);
     
    void clean(void);
    int read_string(char*, const int);
    long read_long(long*);
     
     
    int main(int argc, char *argv[])
    {
        int c, ret;
        char option = ' ';
     
        File my_file;
     
        c = getopt(argc, argv, "c:r:w:");
     
        if(c != EOF)
        {
    	option = c;
    	strncpy(my_file.path, optarg, sizeof(my_file.path));
        }
     
        ret = treat(&my_file, &option);
     
        if(ret == FAIL)
    	return EXIT_FAILURE;
     
        return EXIT_SUCCESS;
    }
     
    int treat(File* my_file, char* option)
    {
        if(*option == ' ')
        {
    	if(get_option(option) == FAIL)
    	    return FAIL;
     
    	if(get_filename(my_file) == FAIL)
    	    return FAIL;
        }
     
        if(*option == 'r' && open_file(my_file, "r") == SUCCESS)
    	return read_file(my_file);
     
        if(*option == 'c' && open_file(my_file, "w") == SUCCESS)
    	return create_file(my_file);
     
        if(*option == 'w' && open_file(my_file, "w") == SUCCESS)
    	return write_file(my_file);
     
        else
        {
    	*option = ' ';
    	return (again() == SUCCESS) ? treat(my_file, option) : FAIL;	
        }
     
        return SUCCESS;    
    }
     
    int get_option(char* option)
    {
        long ret;
     
        printf("\n\n          zReader - Manipulez vos fichiers"
    	   "\n\n\n   MENU\n"
               " 1 - Lire un fichier\n"
               " 2 - Créer un fichier\n"
               " 3 - Ecrire dans un fichier\n\n");
        do
        {
            printf(" Votre choix ? ");
            if(read_long(&ret) == FAIL)
    	    return FAIL;
     
    	if(ret == 1)
    	    *option = 'r';
     
    	else if(ret == 2 || ret == 3)
    	    *option = 'w';
     
        } while(ret <= 0 || ret >= 4);
     
        return SUCCESS;    
    }
     
    int get_filename(File* my_file)
    {
        printf("\n Entrez le nom du fichier concerné : ");
     
        if(read_string(my_file->path, MAX_LEN) == FAIL)
    	 return FAIL;
     
        return SUCCESS;
    }
     
    int read_file(File* my_file) /* Lis un fichier */
    {
        char str[MAX_LEN] = "";
     
        printf("\n Contenu du fichier : \n\n");
     
        if(fgetc(my_file->ptr) != EOF)
        {
            fseek(my_file->ptr, 0, SEEK_SET);
     
            while(fgets(str, sizeof(str), my_file->ptr) != NULL)
                printf("%s", str);
        }
     
        else
            printf(" Désolé, le fichier est vide !\n");
     
        close_file(my_file);
     
        return SUCCESS;
    }
     
    int create_file(File* my_file) /* Crée un fichier */
    {
        printf("\n Le fichier a été créé avec succès !\n");
     
        close_file(my_file);
     
        return SUCCESS;
    }
     
    int write_file(File* my_file) /* Ecrit dans un fichier */
    {
        char str[MAX_LEN * 5] = "";
     
        printf("\n Saisissez le texte à mettre dans le fichier (pour fermer, tapez \"close_file\") : \n\n");
     
        while(fgets(str, sizeof(str), stdin) != NULL)
        { 
            if(strstr(str, "close_file"))
                break;
     
            fputs(str, my_file->ptr);
        } 
     
        close_file(my_file);
     
        return SUCCESS;
    }
     
    int open_file(File* my_file, const char* mode)
    {
        if((my_file->ptr = fopen(my_file->path, mode)) != NULL)
    	return SUCCESS;
     
        return FAIL;
    }
     
    void close_file(File* my_file)
    {
        fclose(my_file->ptr);
    }
     
    int again(void)
    {
        int c;
     
        do
        {
    	printf("\n Erreur. Recommencer ? (o/n) ");
        	c = fgetc(stdin);
        	clean();
        } while(c != 'o' && c != 'n');
     
        return(c == 'o') ? SUCCESS : FAIL;
    }
     
    void clean(void) /* Nettoie le buffer */
    {
        int c = 0;
        while ((c = getchar()) != '\n' && c != EOF);
    }
     
    int read_string(char *str, const int length) /* Lis une chaîne de caractère */
    {
        char *ptr = NULL;
     
        if(fgets(str, length, stdin) != NULL)
        {
            ptr = strchr(str, '\n');
     
            if(ptr != NULL)
                *ptr = '\0';
     
            else
                clean();
     
            return SUCCESS;
        }
     
        else
        {
            clean(); 
     
            return FAIL;
        }
    }
     
    long read_long(long* ret) /* Lis un long */
    {
        char str[MAX_LEN] = {0};
     
        if(read_string(str, 100))
        {
            *ret = strtol(str, NULL, BASE);
            return SUCCESS;
        }
     
        return FAIL;
    }
     
    void fail_arg(void) /* Si l'utilisateur a rentré des arguments invalides */
    {
        printf(" Arguments invalides.\n Format : -[mode][chemin du fichier]. \n mode = -c (créer), -w (écrire) ou -r (lire).");
    }

Discussions similaires

  1. pb avec un programme de manipulation des fichiers
    Par El Mou dans le forum Débuter
    Réponses: 8
    Dernier message: 27/12/2011, 09h30
  2. Programmation pour manipuler des fichiers XML
    Par anolo40 dans le forum Débuter
    Réponses: 8
    Dernier message: 09/08/2011, 22h29
  3. Réponses: 5
    Dernier message: 18/10/2009, 13h42
  4. Réponses: 2
    Dernier message: 18/01/2003, 17h06

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