[C][Améliorations] Manipulations de fichiers
lucas-84
Messages postés
35
Date d'inscription
Statut
Membre
Dernière intervention
-
lucas-84 Messages postés 35 Date d'inscription Statut Membre Dernière intervention -
lucas-84 Messages postés 35 Date d'inscription Statut Membre Dernière intervention -
Bonjour,
Je vous présente un petit programme de manipulation de fichiers. Je suis à la recherche de remarques, critiques, etc, vu que je ne programme que depuis un an.
Voici le code :
Merci d'avance et bonne journée à vous tous,
lucas-84
Je vous présente un petit programme de manipulation de fichiers. Je suis à la recherche de remarques, critiques, etc, vu que je ne programme que depuis un an.
Voici le code :
/** * \file main.c * \brief gere les arguments du main() * \author lucas-84 * \version 0.1 * \date 24/10/2011 * * Gere les arguments du main() d'un programme de manipulation de fichiers. * */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "error.h" #include "file.h" /** * \fn int main (void) * \brief Entrée du programme. * * \return EXIT_FAILURE en cas d'erreur, EXIT_SUCCESS sinon. */ int main (int argc, char *argv[]) { const char *args[] = {"-c", "-r", "-w"}; ret_e (*handle_file) (const char *); if (argc <= 1) { PRINT_ERROR_ARG_MAIN (); return EXIT_FAILURE; } if (strcmp (argv[1], args[0]) == 0) { handle_file = create_file; } else if (strcmp (argv[1], args[1]) == 0) { handle_file = read_file; } else if (strcmp (argv[1], args[2]) == 0) { handle_file = write_file; } else { PRINT_ERROR_ARG_MAIN (); return EXIT_FAILURE; } if (handle_file (argv[2]) == RET_ERROR) { return EXIT_FAILURE; } return EXIT_SUCCESS; }
/**************************************************************************** Name ........ : file.c Role ........ : handles files Author ..... : lucas-84 Version ..... : V0.1 on 24/10/2011 Compilation : gcc -Wall -pedantic -std=c99 -o zReader main.c file.c error.c Execution : ./zReader [OPTIONS] [FILE] ****************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "error.h" #include "file.h" /** * \fn static ret_e open_file (const char *path, const char *mode) * \brief Ouvre un fichier * * \param path pointeur vers une chaine de caractere indiquant le chemin du * fichier a creer. * \param mode pointeur vers une chaine de caractere indiquant le mode * d'ouverture du fichier a creer. * \return NULL en cas d'erreur, le fichier ouvert sinon. */ /*@null@*/ static FILE *open_file (const char *path, const char *mode) { FILE *f = NULL; if ((f = fopen (path, mode)) == NULL) { PRINT_ERROR ("fopen"); return NULL; } return f; } /** * \fn static ret_e close_file (FILE *f) * \brief Ferme un fichier * * \param f fichier a fermer. * \return RET_ERROR en cas d'erreur, RET_SUCCESS sinon. */ static ret_e close_file (FILE *f) { if (fclose (f) == EOF) { PRINT_ERROR ("fclose"); return RET_ERROR; } return RET_SUCCESS; } /** * \fn ret_e create_file (const char *path) * \brief Cree un fichier * * \param path pointeur vers une chaine de caractere indiquant le chemin du * fichier a creer. * \return RET_ERROR en cas d'erreur, RET_SUCCESS sinon. */ ret_e create_file (const char *path) { FILE *f = NULL; if ((f = open_file (path, "w")) == NULL) { return RET_ERROR; } if (close_file (f) == RET_ERROR) { return RET_ERROR; } return RET_SUCCESS; } /** * \fn ret_e read_file (const char *path) * \brief Lit un fichier * * \param path pointeur vers une chaine de caractere indiquant le chemin du * fichier a creer. * \return RET_ERROR en cas d'erreur, RET_SUCCESS sinon. */ ret_e read_file (const char *path) { FILE *f = NULL; int c; if ((f = open_file (path, "r")) == NULL) { return RET_ERROR; } while ((c = fgetc (stdin)) != EOF) { (void) fprintf (stdout, "%c", c); } if (close_file (f) == RET_ERROR) { return RET_ERROR; } return RET_SUCCESS; } /** * \fn ret_e write_file (const char *path) * \brief Ecrit un fichier * * \param path pointeur vers une chaine de caractere indiquant le chemin du * fichier a creer. * \return RET_ERROR en cas d'erreur, RET_SUCCESS sinon. */ ret_e write_file (const char *path) { FILE *f = NULL; char s[LINE_MAX] = ""; if ((f = open_file (path, "a+")) == NULL) { return RET_ERROR; } (void) fprintf (stdout, "\"/quit\" to stop\n"); while (fgets (s, (int) sizeof (s), stdin) != NULL && strstr (s, "/quit") == 0) { (void) fputs (s, f); } if (close_file (f) == RET_ERROR) { return RET_ERROR; } return RET_SUCCESS; }
/**************************************************************************** Name ........ : file.h Role ........ : declares file.c functions Author ..... : lucas-84 Version ..... : V0.1 on 24/10/2011 Compilation : gcc -Wall -pedantic -std=c99 -o zReader main.c file.c error.c Execution : ./zReader [OPTIONS] [FILE] ****************************************************************************/ #ifndef FILE_H #define FILE_H #include "error.h" #define LINE_MAX 512 ret_e create_file (const char *); ret_e read_file (const char *); ret_e write_file (const char *); #endif
/**************************************************************************** Name ........ : error.h Role ........ : declares error.c functions Author ..... : lucas-84 Version ..... : V0.1 on 24/10/2011 Compilation : gcc -Wall -pedantic -std=c99 -o zReader main.c file.c error.c Execution : ./zReader [OPTIONS] [FILE] ****************************************************************************/ #ifndef ERROR_H #define ERROR_H #include <errno.h> #include <stdio.h> #include <string.h> #define PRINT_ERROR(s) \ do { \ (void) fprintf(stderr, "----------------------------------------" \ "----------------------------------------\n" \ "\t\t\t\t\tERROR\n\n" \ "Fonction : %s\n" \ "File : %s\n" \ "Line : %d\n" \ "Description : %s\n" \ "----------------------------------------" \ "----------------------------------------\n", \ s, __FILE__, __LINE__, strerror(errno)); \ } while (0) #define PRINT_ERROR_ARG_MAIN() \ do { \ (void) fputs ("----------------------------------------" \ "----------------------------------------\n" \ "\t\t\t\t\tERROR\n\n" \ "Invalid argument.\n" \ "Synopsis : ./zReader [OPTIONS] [FILE]\n" \ "Options :\n" \ " -c : create file\n" \ " -r : read file\n" \ " -w : write file\n" \ "----------------------------------------" \ "----------------------------------------\n", stdout); \ } while (0) #define PRINT_ERROR_ARG_FUNCTION(s) \ do { \ (void) fprintf(stderr, "----------------------------------------" \ "----------------------------------------\n" \ "\t\t\t\t\tERROR\n\n" \ "Fonction : %s\n" \ "File : %s\n" \ "Line : %d\n" \ "Description : bad argument\n" \ "----------------------------------------" \ "----------------------------------------\n", \ s, __FILE__, __LINE__); \ } while (0) /** * \enum ret_e * \brief Constantes d'erreurs. * * Str_err_e est un type de retour des fonctions de file.c indiquant si une * erreur s'est produite ou pas. */ typedef enum { RET_ERROR = -1, RET_SUCCESS = 1 } ret_e; #endif
Merci d'avance et bonne journée à vous tous,
lucas-84
A voir également:
- [C][Améliorations] Manipulations de fichiers
- Explorateur de fichiers - Guide
- Renommer des fichiers en masse - Guide
- Fichiers epub - Guide
- Gestionnaire de fichiers - Télécharger - Gestion de fichiers
- Wetransfer gratuit fichiers lourd - Guide
6 réponses
Bonjour,
L'écriture de ton code est bien. C'est bien commenté.
En revanche, je ne suis vraiment pas fan des macros comme tu as fait. Et d'ailleurs ce n'est pas conseillé.
Il vaut mieux utiliser une fonction statique.
Sinon pas grand chose à dire.
L'écriture de ton code est bien. C'est bien commenté.
En revanche, je ne suis vraiment pas fan des macros comme tu as fait. Et d'ailleurs ce n'est pas conseillé.
Il vaut mieux utiliser une fonction statique.
Sinon pas grand chose à dire.
Bonjour,
Essayez une seconde version avec buffer pour la lecture d'un fichier, à la place de getc. En utilisant fseek et fread uniquement quand on arrive au bout du buffer enfin c'est pour remplacer le getc parce que j'ai l'impression que ce sera très long sur les gros fichiers. Pour le fprintf aussi utilisez un buffer et n'affichez que lorsqu'il est plein ou fin du fichier car là il n'est utilisé que pour un seul caractère à la fois alors qu'on sait qu'il va y en avoir bien plus c'est pas le top. Je vous conseil en lecture et écriture de faire comme si vous manipulez du binaire et pas des chaînes de caractères car en fonction des encodages (ceux qui utilisent le caractère null dans le code des caractères par exemple) ça risque de poser des problèmes.
Essayez une seconde version avec buffer pour la lecture d'un fichier, à la place de getc. En utilisant fseek et fread uniquement quand on arrive au bout du buffer enfin c'est pour remplacer le getc parce que j'ai l'impression que ce sera très long sur les gros fichiers. Pour le fprintf aussi utilisez un buffer et n'affichez que lorsqu'il est plein ou fin du fichier car là il n'est utilisé que pour un seul caractère à la fois alors qu'on sait qu'il va y en avoir bien plus c'est pas le top. Je vous conseil en lecture et écriture de faire comme si vous manipulez du binaire et pas des chaînes de caractères car en fonction des encodages (ceux qui utilisent le caractère null dans le code des caractères par exemple) ça risque de poser des problèmes.
Merci à vous pour vos commentaires.
fiddy > pour les macros, c'est un peu embêtant, parce que je suis obligé de les utiliser pour obtenir la valeur de __FILE__ et de __LINE__. Du coup, j'ai fait ça (code pas encore commenté avec Doxygen) :
error.h :
error.c :
Hxyp > j'y réfléchis pour la lecture des fichiers avec le binaire, merci ! Je ne connais pas Trop les fonctions qui s'y rapportent , mais ça me fera apprendre.
fiddy > pour les macros, c'est un peu embêtant, parce que je suis obligé de les utiliser pour obtenir la valeur de __FILE__ et de __LINE__. Du coup, j'ai fait ça (code pas encore commenté avec Doxygen) :
error.h :
/** * \file error.h * \brief macros de gestion des erreurs * \author lucas-84 * \version V0.2 on 25/10/2011 * \date 24/10/2011 * * Declare les fonctions d'error.c et quelques macros de gestion des erreurs. * */ #ifndef ERROR_H #define ERROR_H #define PRINT_ERROR(s) \ do { \ print_error (s, __FILE__, __LINE__) ; \ } while (0) #define PRINT_ERROR_ARG_FUNCTIONS(s) \ do { \ print_error_arg_functions (s, __FILE__, __LINE__); \ } while (0) /** * \enum ret_e * \brief Constantes d'erreurs. * * Str_err_e est un type de retour des fonctions de file.c indiquant si une * erreur s'est produite ou pas. */ typedef enum { RET_ERROR = -1, RET_SUCCESS = 1 } ret_e; void print_error (const char *, const char *, int); void print_error_arg_main (void); void print_error_arg_functions (const char *, const char *, int); #endif
error.c :
/** * \file error.c * \brief fonction de signalisation des erreurs * \author lucas-84 * \version V0.2 on 25/10/2011 * \date 24/10/2011 * * Definit trois fonctions qui signalent a l'utilisateur une erreur. * */ #include <errno.h> #include <stdio.h> #include <string.h> void print_error (const char *s, const char *f, int l) { (void) fprintf(stderr, "----------------------------------------" "----------------------------------------\n" "\t\t\t\t\tERROR\n\n" "Fonction : %s\n" "File : %s\n" "Line : %d\n" "Description : %s\n" "----------------------------------------" "----------------------------------------\n", s, f, l, strerror(errno)); } void print_error_arg_main (void) { (void) fputs ("----------------------------------------" "----------------------------------------\n" "\t\t\t\t\tERROR\n\n" "Invalid argument.\n" "Synopsis : ./zReader [OPTIONS] [FILE]\n" "Options :\n" " -c : create file\n" " -r : read file\n" " -w : write file\n" "----------------------------------------" "----------------------------------------\n", stderr); } void print_error_arg_functions (const char *s, const char *f, int l) { (void) fprintf(stderr, "----------------------------------------" "----------------------------------------\n" "\t\t\t\t\tERROR\n\n" "Fonction : %s\n" "File : %s\n" "Line : %d\n" "Description : bad argument\n" "----------------------------------------" "----------------------------------------\n", s, f, l); }
Hxyp > j'y réfléchis pour la lecture des fichiers avec le binaire, merci ! Je ne connais pas Trop les fonctions qui s'y rapportent , mais ça me fera apprendre.
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
fiddy > pour les macros, c'est un peu embêtant, parce que je suis obligé de les utiliser pour obtenir la valeur de __FILE__ et de __LINE__.
Tu peux très bien faire : printf("__LINE__=%d\n",__LINE__); sans passer par une macro.
Je ne vois pas ce qui t'oblige à utiliser les macros. Peux-tu m'éclairer ?
Tu peux très bien faire : printf("__LINE__=%d\n",__LINE__); sans passer par une macro.
Je ne vois pas ce qui t'oblige à utiliser les macros. Peux-tu m'éclairer ?
Le problème, c'est que si j'utilise les macros directement dans la fonction, j'aurais le fichier et la ligne de ma fonction erreur. Impossible donc de différencier les erreurs.
Alors que la macro s'intègre directement dans le code où l'erreur s'est produite, donc on obtient la ligne où j'appelle mon PRINT_ERROR().
Enfin, il me semble, non ?
Alors que la macro s'intègre directement dans le code où l'erreur s'est produite, donc on obtient la ligne où j'appelle mon PRINT_ERROR().
Enfin, il me semble, non ?