c - 从csv文件读取并分成变量

标签 c file input

我试图将输入值分为两个不同的类别。第一个数组调用teamname将保存团队名称,第二个数组将保存该周的分数。我的输入文件是.csv,代码是以字符串的形式存储的,而不是两个单独的变量。另外,我不懂程序,只熟悉图书馆。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

#define FILEIN "data.csv"
#define FILEOUT "matrix.csv"

int main (void)
{
    double nfl[32][32], teamscore[32];
    char teamname[30];
    int n;
    FILE *filein_ptr;
    FILE *fileout_ptr;

    filein_ptr = fopen (FILEIN, "r");
    fileout_ptr = fopen (FILEOUT, "w");

    for (n = 1; n <= 32; n++) {
        fscanf (filein_ptr, "%s  %lf\n", &teamname, &teamscore[n]);
        fprintf (fileout_ptr, "%s    %f\n", teamname, teamscore);
    }

    fclose (filein_ptr);
    fclose (fileout_ptr);

    return 0;
}

我应该说,输入文件的第一列有团队名称,第二列有团队分数。任何帮助都很好。谢谢!
这是一个示例输入文件
钢人,20
爱国者,25岁
袭击者,15
酋长,35岁

最佳答案

除了将&teamname更改为teamname之外,您可能还需要考虑其他一些因素。首先,总是初始化变量。虽然不是必需的,但这有一些积极的好处。对于数值数组,它初始化所有元素,以防止意外读取未初始化的值。对于字符数组,初始化为0将确保字符串的第一个副本(小于总长度)将null-terminated,并防止尝试读取未初始化的值。这只是个好习惯:

    double teamscore[MAXS] = {0.0};
    char teamname[30] = {0};
    int n = 0;

您已经为filein_ptrfileout_ptr定义了默认值,您可以对数组大小执行相同的操作。如果数组大小需要更改,则只需提供一个值即可更新,从而使代码更易于维护。
接下来,这是一个相当重要的问题。main接受参数,由标准定义为int argc, char **argv(在Unix系统上还可以看到char **envp,看起来它们都是以等效形式编写的char *argv[]char *envp[])。这里的要点是使用它们为程序获取参数,这样您就不会被硬编码的data.csvmatrix.csv文件名所困扰。您可以使用硬编码值,并且仍然可以通过使用简单的ternary运算符(例如test ? if true code : if false code;)为用户提供输入所选文件名的能力:
    FILE *filein_ptr = argc > 1 ? fopen (argv[1], "r") : fopen (FILEIN, "r");
    FILE *fileout_ptr = argc > 2 ? fopen (argv[2], "w") : fopen (FILEOUT, "w");

在这里,测试argc > 1(意味着至少有一个由用户给定的参数),如果是真代码open (argv[1], "r")(打开作为读取参数给定的文件名,如果是假代码fopen (FILEIN, "r"),则打开默认值(如果不是给定的文件名)。输出文件也是如此。(必须按正确顺序提供)。
然后,如果打开一个文件,则必须在尝试读取该文件之前验证该文件是否已实际打开。虽然可以分别测试输入和输出以判断哪一个失败,但也可以使用一个简单的||条件来检查打开是否失败:
    if (!filein_ptr || ! fileout_ptr) {
        fprintf (stderr, "error: filein of fileout open failed.\n");
        return 1;
    }

最后,如果您知道需要读取的数据行数,那么可以使用索引的for循环,但您很少会事先知道数据文件中的行数。即使使用for循环,您仍然需要检查fscanf的返回,以验证您实际上有2个有效的转换(因此得到了您期望的2个值)。检查报税表也提供了另一个好处。它允许您继续阅读,直到您不再从fscanf获得2个有效的转换。这提供了一种从文件中读取未知数量值的简单方法。但是,您确实需要确保不会尝试在数组中读取超出其容量的值。例如。:
    while (fscanf (filein_ptr, " %29[^,],%lf", teamname, &teamscore[n]) == 2) {
        fprintf (fileout_ptr, "%s    %f\n", teamname, teamscore[n++]);
        if (n == MAXS) {  /* check data doesn't exceed MAXS */
            fprintf (stderr, "warning: data exceeds MAXS.\n");
            break;
        }
    }

注意:当使用包含字符大小写的格式说明符(如"%[^,], ...")时,请注意它将读取并在转换为字符串时包含前导和尾随空格。因此,如果您的文件有' Steelers ,..'teamname将包含空白。您可以通过在转换开始之前包括一个空间(如" %29[^,], ..."),并通过指定最大字段宽度来限制可读取的字符数,来修复引导的空白。(本例中的尾随空格在读取后更容易修剪)
将所有的部分放在一起,您可以通过使用来自用户的参数,并验证文件和读取操作,使代码更加灵活和可靠:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

#define FILEIN "data.csv"
#define FILEOUT "matrix.csv"
#define MAXS 32

int main (int argc, char **argv)
{
    /* double nfl[MAXS][MAXS] = {{0}}; */
    double teamscore[MAXS] = {0.0};
    char teamname[30] = {0};
    int n = 0;
    FILE *filein_ptr = argc > 1 ? fopen (argv[1], "r") : fopen (FILEIN, "r");
    FILE *fileout_ptr = argc > 2 ? fopen (argv[2], "w") : fopen (FILEOUT, "w");

    if (!filein_ptr || ! fileout_ptr) {
        fprintf (stderr, "error: filein of fileout open failed.\n");
        return 1;
    }

    while (fscanf (filein_ptr, " %29[^,],%lf", teamname, &teamscore[n]) == 2) {
        fprintf (fileout_ptr, "%s    %f\n", teamname, teamscore[n++]);
        if (n == MAXS) {  /* check data doesn't exceed MAXS */
            fprintf (stderr, "warning: data exceeds MAXS.\n");
            break;
        }
    }

    fclose (filein_ptr);
    fclose (fileout_ptr);

    return 0;
}

测试输入
$ cat ../dat/teams.txt
Steelers,   20
Patriots,25
    Raiders,    15
    Chiefs,35

注意:前导空白和值之间空白的变化是有意的。
使用/输出
$ ./bin/teams ../dat/teams.txt teamsout.txt

$ cat teamsout.txt
Steelers    20.000000
Patriots    25.000000
Raiders    15.000000
Chiefs    35.000000

如果你还有问题,请告诉我。

关于c - 从csv文件读取并分成变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33761409/

相关文章:

在 C 中创建 "classes",在栈上还是在堆上?

c - C11 中类型名称作用域的概念

java - 如何从文本文件中删除特定内容?

C 段错误,大小为 4 的读取无效

c++ - 在函数中获取排序数组和值并将该值放在正确的位置

C++,如何更新文本文件中的文本?

c - 从链接列表保存到文件并将其加载回来

input - Flutter TextField Widget 下出现奇怪的红色 block

html 表单输入 - 每个输入字段的多个答案

powershell - bat 文件禁止用户输入