[C][Améliorations] Manipulations de fichiers

Fermé
lucas-84 Messages postés 35 Date d'inscription dimanche 17 octobre 2010 Statut Membre Dernière intervention 7 décembre 2011 - 24 oct. 2011 à 17:24
lucas-84 Messages postés 35 Date d'inscription dimanche 17 octobre 2010 Statut Membre Dernière intervention 7 décembre 2011 - 27 oct. 2011 à 12:32
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 :

/**
 * \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:

6 réponses

fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 843
24 oct. 2011 à 20:56
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.
0
Hxyp Messages postés 401 Date d'inscription vendredi 28 janvier 2011 Statut Membre Dernière intervention 27 avril 2014 54
24 oct. 2011 à 23:31
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.
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 843
25 oct. 2011 à 08:22
Hxyp,
Pas besoin pour printf sur stdout.
Cdlt
0
lucas-84 Messages postés 35 Date d'inscription dimanche 17 octobre 2010 Statut Membre Dernière intervention 7 décembre 2011 6
Modifié par lucas-84 le 25/10/2011 à 09:51
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 :

/**   
 * \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.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 843
25 oct. 2011 à 20:19
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 ?
0
lucas-84 Messages postés 35 Date d'inscription dimanche 17 octobre 2010 Statut Membre Dernière intervention 7 décembre 2011 6
27 oct. 2011 à 12:32
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 ?
0