从C语言的文本文件中读取信息

发布于 2024-10-02 22:23:50 字数 639 浏览 2 评论 0原文

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

这是一个示例文件:

#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

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

I'm new to C; please try to help me as much as you can.
I'm getting as arguments to main() pointers to files,
so in a for loop I fopen() them and want to send them to a function that will
read the text info inside them and put it in char variables.

Here is an example file:

#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

The text has fields separated with commas, and I need the information between those commas to be added to vars.
What will be the best way or function to read these text files?
Also should I expect '\n' after each line or will it stream as one big char[] without the new line character?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

陈独秀 2024-10-09 22:23:50

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

read file line by line
use strtok function to get everything in between commas

花伊自在美 2024-10-09 22:23:50

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

read file line by line and use sscanf with return-value to get everything in between commas

挽容 2024-10-09 22:23:50

稍后大约 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, §ion->header);
    for (size_t i = 0; i < section->num_rows; i++)
        dump_line(fp, §ion->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(§ion->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;
}

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

Some 200 lines of code later...and using a slightly modified version of your data file (note that the second header line in the original is missing all the commas):

#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, §ion->header);
    for (size_t i = 0; i < section->num_rows; i++)
        dump_line(fp, §ion->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(§ion->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;
}

The code is not optimal in most senses - it allocates far too many small bits of memory. I also got lazy and didn't write the code to free the memory. I don't think it would be a good idea to hand this in as your code, though.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文