【问题标题】:Reading information from text file in C从C中的文本文件中读取信息
【发布时间】:2026-01-31 22:25:01
【问题描述】:

我是 C 新手;请尽量帮助我。 我得到main()指向文件的指针作为参数, 所以在一个 for 循环中,我 fopen() 他们并希望将它们发送到一个函数,该函数将 读取其中的文本信息并将其放入 char 变量中。

这是一个示例文件:

#站名 车站名称:A1 #octan 燃料 6.54 全方位服务价格 6.40 自助服务 Octan95,6.54,6.40 Octan98,8.30,8.15 #carNum,Octan,numOfLiters,服务种类 22-334-55,95,31.3,全方位服务 22-334-55,95,31.3,自助服务 11-444-77,95,12,全方位服务 11-444-77,95,44.1,全方位服务 11-444-77,95,11.22,自助服务

文本具有用逗号分隔的字段,我需要将这些逗号之间的信息添加到变量中。 阅读这些文本文件的最佳方式或功能是什么? 我还应该在每一行之后期待'\n',还是会在没有换行符的情况下作为一个大char[] 流式传输?

【问题讨论】:

  • 你写了什么?你打算使用什么数据结构?格式的可变性如何(其他文件是否有不同的列集,或者列集是否都是固定的)?数据读入后需要做什么?
  • 要回答您的最后一个问题,您应该在每行之后添加一个换行符 - 假设您使用 fgets() 逐行读取文件。

标签: c file input


【解决方案1】:

逐行读取文件 使用 strtok 函数获取逗号之间的所有内容

【讨论】:

  • strtok 切换空的逗号分隔字段
【解决方案2】:

逐行读取文件并使用带有返回值的 sscanf 来获取逗号之间的所有内容

【讨论】:

    【解决方案3】:

    大约 200 行代码之后......并使用稍微修改过的数据文件版本(请注意,原始文件中的第二个标题行缺少所有逗号):

    #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;
    }
    

    代码在大多数意义上都不是最优的——它分配了太多的小内存。我也很懒,没有写代码来释放内存。不过,我认为将其作为您的代码提交并不是一个好主意。

    【讨论】: