我想读取一个 csv 文件并将其加载到一个结构数组中。我使用了在 youtube 和 github 上找到的代码 (https://github.com/portfoliocourses/c-example-code/blob/main/csv_to_struct_array.c)。现在我想将结构的所有成员更改为字符数组(或字符串)。如果我按顺序更改每个结构(至少成员
type
和age
),这会起作用,但是如果我将成员average
更改为字符数组,我会收到错误消息File format incorrect
。我怀疑它是因为在EOF
循环期间文件中的字符while (!feof(file));
有问题。我该如何解决这个问题?
这里是原代码:
/*******************************************************************************
*
* Program: Read CSV File Data To An Array Of Structs
*
* Description: Example of reading CSV file data into an array of structs in C.
*
* YouTube Lesson: https://www.youtube.com/watch?v=rbVt5v8NNe8
*
* Author: Kevin Browne @ https://portfoliocourses.com
*
*******************************************************************************/
#include <stdio.h>
// A struct for representing student data in a file formatted like this:
//
// U,Virat Kohli,23,95.6
// U,Serena Williams,22,83.2
// G,Wayne Gretzky,19,84.2
//
// with a "student type" (e.g. undergraduate, graduate) single character,
// followed by the student's name, age and then average.
//
typedef struct
{
// members for the student's type, name, age and average
char type;
char name[50];
int age;
double average;
} Student;
int main(void)
{
// file pointer variable for accessing the file
FILE *file;
// attempt to open file.txt in read mode to read the file contents
file = fopen("file.txt", "r");
// if the file failed to open, exit with an error message and status
if (file == NULL)
{
printf("Error opening file.\n");
return 1;
}
// array of structs for storing the Student data from the file
Student students[100];
// read will be used to ensure each line/record is read correctly
int read = 0;
// records will keep track of the number of Student records read from the file
int records = 0;
// read all records from the file and store them into the students array
do
{
// Read a line/record from the file with the above format, notice in
// particular how we read in the student's name with %49[^,] which matches
// up to 49 characters NOT including the comma (so it will stop matching
// at the next comma). The name member can store 50 characters, so
// factoring in the NULL terminator this is the maximum amount of characters
// we can read in for a number. fscanf() will return the number of values
// it was able to read successfully which we expect to be 4, and we store
// that into read.
//
read = fscanf(file,
"%c,%49[^,],%d,%lf\n",
&students[records].type,
students[records].name,
&students[records].age,
&students[records].average);
// if fscanf read 4 values from the file then we've successfully read
// in another record
if (read == 4) records++;
// The only time that fscanf should NOT read 4 values from the file is
// when we've reached the end of the file, so if fscanf did not read in
// exactly 4 values and we're not at the end of the file, there has been
// an error (likely due to an incorrect file format) and so we exit with
// an error message and status.
if (read != 4 && !feof(file))
{
printf("File format incorrect.\n");
return 1;
}
// if there was an error reading from the file exit with an error message
// and status
if (ferror(file))
{
printf("Error reading file.\n");
return 1;
}
} while (!feof(file));
// close the file as we are done working with it
fclose(file);
// print out the number of records read
printf("\n%d records read.\n\n", records);
// print out each of the records that was read
for (int i = 0; i < records; i++)
printf("%c %s %d %.2f\n",
students[i].type,
students[i].name,
students[i].age,
students[i].average);
printf("\n");
return 0;
}
这里是修改后的代码:
#include <stdio.h>
typedef struct
{
//char type; \\original commented code
//char name[50]; \\original commented code
//int age; \\original commented code
//double average; \\original commented code
char type[50];
char name[50];
char age[50];
char average[50];
} Student;
int main(void)
{
FILE *file;
file = fopen("file.txt", "r");
if (file == NULL)
{
printf("Error opening file.\n");
return 1;
}
Student students[100];
int read = 0;
int records = 0;
do
{
read = fscanf(file,
//"%c,%49[^,],%d,%lf\n" \\original commented code
"%49[^,],%49[^,],%49[^,],%49[^,]\n",
students[records].type,
students[records].name,
students[records].age,
students[records].average);
//students[records].average);
if (read == 4) records++;
if (read != 4 && !feof(file))
{
printf("File format incorrect.\n");
return 1;
}
if (ferror(file))
{
printf("Error reading file.\n");
return 1;
}
} while (!feof(file));
fclose(file);
printf("\n%d records read.\n\n", records);
for (int i = 0; i < records; i++)
//printf("%c %s %d %.2f\n", \\original commented code
printf("%s %s %s %.s\n",
students[i].type,
students[i].name,
students[i].age,
students[i].average);
printf("\n");
return 0;
}
编辑1 我改变了
" %49[^,],%49[^,],%49[^,],%49[^\n]",
得到这个输出:
3 records read.
U Virat Kohli 23
U Serena Williams 22
G Wayne Gretzky 19
在可以解析文件但最后一列(或每行最后一个逗号之后的项目)消失的意义上有所改进,因为它应该是:
3 records read.
U Virat Kohli 23 95.60
U Serena Williams 22 83.20
G Wayne Gretzky 19 84.20
这里是修改版的源码
#include <stdio.h>
typedef struct
{
//char type; \\original commented code
//char name[50]; \\original commented code
//int age; \\original commented code
//double average; \\original commented code
char type[50];
char name[50];
char age[50];
char average[50];
} Student;
int main(void)
{
FILE *file;
file = fopen("file.txt", "r");
if (file == NULL)
{
printf("Error opening file.\n");
return 1;
}
Student students[100];
int read = 0;
int records = 0;
do
{
read = fscanf(file,
//"%c,%49[^,],%d,%lf\n" \\original commented code
//"%49[^,],%49[^,],%49[^,],%49[^,\n]",
" %49[^,],%49[^,],%49[^,],%49[^\n]",
students[records].type,
students[records].name,
students[records].age,
students[records].average);
//students[records].average);
if (read == 4) records++;
if (read != 4 && !feof(file))
{
printf("File format incorrect.\n");
return 1;
}
if (ferror(file))
{
printf("Error reading file.\n");
return 1;
}
} while (!feof(file));
fclose(file);
printf("\n%d records read.\n\n", records);
for (int i = 0; i < records; i++)
//printf("%c %s %d %.2f\n", \\original commented code
printf("%s %s %s %.s\n",
students[i].type,
students[i].name,
students[i].age,
students[i].average);
printf("\n");
return 0;
}
附源码记录
file.txt
(复制自原代码):
U,Virat Kohli,23,95.6
U,Serena Williams,22,83.2
G,Wayne Gretzky,19,84.2
像这样重写格式字符串
" %49[^,],%49[^,],%49[^,],%49[^\n]",
注意格式化字符串中的前导空格。它允许跳过空白字符。
我假设整个记录没有以逗号结尾。
另一种方法是声明一个足够大的字符数组来存储文件中的一条记录,并使用
fgets
而不是 scanf
。然后,您可以使用 strtok
或 sscanf
解析获得的记录。
也在
printf
的呼唤中
printf("%s %s %s %.s\n",
students[i].type,
students[i].name,
students[i].age,
students[i].average);
有不正确的转换说明符
%.s
。相反,只需写%s
.