2010-11-14 6 views
0

Je suis nouveau chez C; S'il vous plaît essayez de m'aider autant que vous le pouvez. Je reçois comme arguments à main() pointeurs vers des fichiers, donc dans une boucle pour fopen() je les et je veux les envoyer à une fonction qui va lire les informations de texte à l'intérieur d'eux et le mettre en variables char.Lecture d'informations à partir d'un fichier texte en C

Voici un exemple de fichier:

 
#station name 
Station Name : A1 
#octan of fuel 6.54 full service price 6.40 self service 
Octan95,6.54,6.40 
Octan98,8.30,8.15 
#carNum,Octan,numOfLiters,Kind of service 
22-334-55,95,31.3,FullService 
22-334-55,95,31.3,SelfService 
11-444-77,95,12,FullService 
11-444-77,95,44.1,FullService 
11-444-77,95,11.22,SelfService 

Le texte comporte des champs séparés par des virgules, et je besoin des informations entre les virgules à ajouter à vars. Quelle sera la meilleure façon ou fonction de lire ces fichiers texte? Devrais-je m'attendre à '\n' après chaque ligne ou va-t-elle diffuser en tant que grand char[] sans le caractère de nouvelle ligne?

+2

Qu'avez-vous écrit? Quelles structures de données envisagez-vous d'utiliser? Quelle est la variable des formats (les autres fichiers auront-ils des ensembles de colonnes différents, ou les ensembles de colonnes seront-ils tous corrigés)? Que devez-vous faire après la lecture des données? –

+0

Pour répondre à votre dernière question, vous devriez vous attendre à un retour à la ligne après chaque ligne - en supposant que vous utilisiez 'fgets()' pour lire le fichier en lignes. –

Répondre

0

ligne de fichier de lecture par ligne utiliser la fonction strtok pour obtenir tout le reste des virgules

+0

strtok bascule sur des champs vides délimités par des virgules – user411313

0

ligne de fichier de lecture par ligne et utiliser sscanf avec la valeur de retour pour obtenir tout le reste des virgules

0

Quelque 200 lignes de code plus tard ... et en utilisant une version légèrement modifiée de votre fichier de données (notez que la deuxième ligne d'en-tête dans l'original est manquant tous les virgules):

#include <assert.h> 
#include <errno.h> 
#include <stdarg.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

/* 
** Example data: 
** 
** #station name 
** Station Name : A1 
** #octan of fuel,full service price,self service price 
** Octan95,6.54,6.40 
** Octan98,8.30,8.15 
** #carNum,Octan,numOfLiters,Kind of service 
** 22-334-55,95,31.3,FullService 
** 22-334-55,95,31.3,SelfService 
** 11-444-77,95,12,FullService 
** 11-444-77,95,44.1,FullService 
** 11-444-77,95,11.22,SelfService 
** 
** - Header lines are followed by one or more data lines 
** - Number of fields in header matches number of fields in each data line 
** - Commas separate fields and do not appear within fields (not full CSV) 
*/ 

/* A Line structure holds the fields for one line */ 
typedef struct Line 
{ 
    size_t num_fields; 
    char **fields; 
} Line; 

/* A Section structure holds the header line and the set of data lines */ 
typedef struct Section 
{ 
    size_t num_rows; 
    size_t num_cols; 
    Line header; 
    Line *lines; /* Array of lines - num_rows entries in array */ 
} Section; 

/* An Info structure holds all the sections for a single file */ 
typedef struct Info 
{ 
    size_t num_sections; 
    Section *sections; 
} Info; 

static void err_exit(const char *format, ...) 
{ 
    va_list args; 
    va_start(args, format); 
    vfprintf(stderr, format, args); 
    va_end(args); 
    exit(1); 
} 

static void *xrealloc(void *old_data, size_t nbytes) 
{ 
    void *new_data = realloc(old_data, nbytes); 
    if (new_data == 0) 
     err_exit("Out of memory!\n"); 
    return new_data; 
} 

static void *xmalloc(size_t nbytes) 
{ 
    void *new_data = malloc(nbytes); 
    if (new_data == 0) 
     err_exit("Out of memory!\n"); 
    return new_data; 
} 

/* Duplicate a string of given length (excluding NUL) */ 
static char *xstrndup(const char *str, size_t len) 
{ 
    char *new_data = xmalloc(len+1); 
    memmove(new_data, str, len); 
    new_data[len] = '\0'; 
    return new_data; 
} 

static void dump_line(FILE *fp, const Line * const line) 
{ 
    size_t i; 
    const char *pad = ""; 
    for (i = 0; i < line->num_fields; i++) 
    { 
     fprintf(fp, "%s%*s", pad, 1, line->fields[i]); 
     pad = " "; 
    } 
    fputc('\n', fp); 
} 

static void dump_section(FILE *fp, const char *tag, const Section * const section) 
{ 
    if (tag != 0) 
     fprintf(fp, "Dump Section: %s\n", tag); 
    fprintf(fp, "Number of columns: %zd\n", section->num_cols); 
    fprintf(fp, "Number of lines: %zd\n", section->num_rows); 
    dump_line(fp, &section->header); 
    for (size_t i = 0; i < section->num_rows; i++) 
     dump_line(fp, &section->lines[i]); 
} 

static void dump_info(FILE *fp, const char *tag, const Info * const info) 
{ 
    size_t i; 

    fprintf(fp, "Dump Information: %s\n", tag); 
    fprintf(fp, "Number of sections: %zd\n", info->num_sections); 
    for (i = 0; i < info->num_sections; i++) 
    { 
     char title[20]; 
     snprintf(title, sizeof(title), "%d", i+1); 
     dump_section(fp, title, &info->sections[i]); 
    } 
    fprintf(fp, "End of Information Dump\n"); 
} 

static int num_fields(const char *buffer) 
{ 
    size_t posn = 0; 
    size_t next; 
    int count = 0; 
    while ((next = strcspn(buffer + posn, ",\n")) > 0) 
    { 
     count++; 
     if (buffer[posn+next] == '\n') 
      break; 
     posn += next + 1; 
    } 
    return count; 
} 

static void set_line(Line *line, int nfields, const char *buffer) 
{ 
    size_t posn = 0; 
    line->num_fields = nfields; 
    line->fields = xmalloc(nfields * sizeof(*line->fields)); 
    for (int i = 0; i < nfields; i++) 
    { 
     size_t next = strcspn(buffer+posn, ",\n"); 
     line->fields[i] = xstrndup(buffer+posn, next); 
     if (buffer[posn+next] == '\n') 
     { 
      if (i != nfields - 1) 
       err_exit("Internal error: field count mismatch\n"); 
      break; 
     } 
     posn += next + 1; 
    } 
} 

static int add_section(Info *info, char *buffer) 
{ 
    int nfields = num_fields(buffer); 
    int nsections = info->num_sections + 1; 
    info->sections = xrealloc(info->sections, nsections * sizeof(*info->sections)); 
    info->num_sections = nsections; 
    Section *new_section = &info->sections[nsections-1]; 
    new_section->num_cols = nfields; 
    new_section->num_rows = 0; 
    set_line(&new_section->header, nfields, buffer); 
    new_section->lines = 0; 
    return nfields; 
} 

/* Beware - very compact code! */ 
static void add_line_to_section(Section *section, const char *buffer, int nfields) 
{ 
    section->lines = xrealloc(section->lines, (section->num_rows + 1) * sizeof(*section->lines)); 
    set_line(&section->lines[section->num_rows++], nfields, buffer); 
} 

static int peek(FILE *fp) 
{ 
    int c; 
    if ((c = getc(fp)) != EOF) 
     ungetc(c, fp); 
    return c; 
} 

static void read_info(FILE *fp, Info *info) 
{ 
    char buffer[1024]; 
    while (fgets(buffer, sizeof(buffer), fp) != 0) 
    { 
     if (*buffer != '#') 
      err_exit("Format error: expected line beginning '#' (got '%.*s')\n", 
        10, buffer); 
     int nfields = add_section(info, buffer+1); 
     int c; 
     Section *cursect = &info->sections[info->num_sections-1]; 
     while ((c = peek(fp)) != EOF && c != '#') 
     { 
      if (fgets(buffer, sizeof(buffer), fp) != 0) 
      { 
       int lfields = num_fields(buffer); 
       if (lfields != nfields) 
        err_exit("Mismatch in number of fields (got %d, wanted %) at '%*s'\n", 
          lfields, nfields, 20, buffer); 
       add_line_to_section(cursect, buffer, nfields); 
      } 
     } 
    } 
} 

int main(int argc, char **argv) 
{ 
    int i; 
    Info info = { 0, 0 }; 

    for (i = 1; i < argc; i++) 
    { 
     FILE *fp; 
     if ((fp = fopen(argv[i], "r")) != 0) 
     { 
      read_info(fp, &info); 
      dump_info(stdout, "After loop", &info); 
     } 
     else 
      fprintf(stderr, "Failed to open file %s (%s)\n", argv[i], strerror(errno)); 
    } 
    dump_info(stdout, "End of main loop", &info); 
    return 0; 
} 

le code n'est pas optimale dans la plupart des sens - il attribue loin à o beaucoup de petits morceaux de mémoire. J'ai aussi été paresseux et n'ai pas écrit le code pour libérer la mémoire. Cependant, je ne pense pas que ce serait une bonne idée d'inclure cela dans votre code.

Questions connexes