如何将所有csv文件数据顺序读入一个结构体数组?

zbwhf8kr  于 11个月前  发布在  其他
关注(0)|答案(2)|浏览(100)

我想读一个.csv文件。我已经学习了解析和使用strtok来解析。我也已经写了代码,但我的代码不能正常工作。我的代码只读取一部分数据到struct的数组,另一部分没有写入struct的数组。我的代码还奇怪地从2931行读取数据,而不是从开头读取。
这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    char location[100];
    char city[100];
    int price;
    int room;
    int bathroom;
    int carpark;
    char type[100];
    char furnish[100];
} data;

int main() {

    data house[4000];

    FILE *file = fopen("data.csv", "r");
    char buffer[1000];
    fgets(buffer, 1000, file);
    int n = 0; 
    while (fgets(buffer, 1000, file)) {
        char *token = strtok(buffer, ",");
        strcpy(house[n].location, token);

        token = strtok(NULL, ",");
        strcpy(house[n].city, token);

        token = strtok(NULL, ",");
        house[n].price = atoi(token);

        token = strtok(NULL, ",");
        house[n].room = atoi(token);

        token = strtok(NULL, ",");
        house[n].bathroom = atoi(token);

        token = strtok(NULL, ",");
        house[n].carpark = atoi(token);

        token = strtok(NULL, ",");
        strcpy(house[n].type, token);

        token = strtok(NULL, "\n");
        strcpy(house[n].furnish, token);

        n++;
    }

    fclose(file);

    for (int i = 0; i < n; i++) {
         printf("%s,%s,%d,%d,%d,%d,%s,%s\n",
                house[i].location, house[i].city, house[i].price,
                house[i].room, house[i].bathroom, house[i].carpark,
                house[i].type, house[i].furnish);
    }

    return 0;
}

字符串
这是data.csv的链接我的程序刚刚从实际的3940数据中读取了大约1010数据。This is the image of comparison.
This is from the terminal, which shown the data from line 2931, not from the beginning.
我想我必须提到这一点:在成功地阅读数据后,我想做的是创建一些包含like this的菜单。所以程序可以做一些事情,比如显示数据,搜索数据,排序数据,并在排序后导出数据。在我的代码中使用这样的结构体数组已经正确地完成了我提到的所有任务吗?或者我可以改变一些更有效和更有效率的东西?

cigdeys3

cigdeys31#

要读取文件数据,可以使用fgets库

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
 
const char* getfield(char* line, int num)
{
    const char* data;
    for (data = strtok(line, ";");
            data && *data;
            data = strtok(NULL, ";\n"))
    {
        if (!--num)
            return data;
    }
    return NULL;
}
 
int main()
{
    char line[1024];
    while (fgets(line, 1024, stdin))
    {
        char* tmp = strdup(line);
        printf("Field 3 would be %s\n", getfield(tmp, 3));
        // NOTE strtok clobbers tmp
        free(tmp);
    }
}

字符串
要将css写入文件,可以使用cout方法或ofstream

#include <iostream>
#include <fstream>


int main()
{

    std::ofstream Myfile("boogaloo.txt");

    int width =10, height =10;
      

    for (int w = 0; w< width;w++)
    {   
        for (int h = 0; h < height; h++)
        {
            Myfile << h<< ",";
        }

        Myfile << "\n ";
    }

    Myfile.close();
    return 0;
}


你的代码看起来很好,但你的控制台是运行出来的行打印数据到.所以点击控制台,如果在Windows上转到比例和增加缓冲区大小打印到.我做了它与缓冲区高度.

quhf5bfb

quhf5bfb2#

strtok可能不适合解析CSV内容:连续的分隔符序列将被视为单个分隔符。这对于空白可能是可以的,但对于,则不行,因为空字段将导致解析器的反序列化。在任何情况下,在将strtok()的返回值传递给atoi()strcpy之前,都应该检查它们是否为空。
您也可以使用sscanf()在一个步骤中解析该行并报告解析失败,但sscanf()也不能解析空字段。它仍然是检查无效记录的更简单的方法。
还请注意这些备注:

  • 你必须检查fopen故障是否报告有意义的消息
  • 读取的记录数不能超过目标数组中的记录数
  • strcpy可能会导致缓冲区溢出,因为您没有检查字符串字段是否适合目标数组。
  • 分配1665000字节的自动存储可能超过您的目标环境限制。请考虑分配house对象。

下面是一个修改后的版本,它将报告无效的CSV记录:

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

typedef struct {
    char location[100];
    char city[100];
    int price;
    int room;
    int bathroom;
    int carpark;
    char type[100];
    char furnish[100];
} data;

int main(void) {

    int max_n = 4000;
    data *house = calloc(sizeof(*house), max_n);
    if (house == NULL) {
        fprintf(stderr, "cannot allocate database\n");
        return 1;
    }

    FILE *file = fopen("data.csv", "r");
    if (file == NULL) {
        fprintf(stderr, "cannot open %s: %s\n", "data.csv", strerror(errno));
        free((house);
        return 1;
    }
    char buffer[1000];
    int lineno = 1;
    if (!fgets(buffer, sizeof buffer, file)) {
        fprintf(stderr, "%s:empty file\n", "data.csv");
        fclose(file);
        free((house);
        return 1;
    }
    int n = 0; 
    while (n < max_n && fgets(buffer, sizeof buffer, file)) {
        char eol[2];
        lineno++;
        if (sscanf(buffer, "%99[^,],%99[^,],%d,%d,%d,%d,%99[^,],%99[^,\n]%1[\n]",
            house[n].location, house[n].city, &house[n].price,
            &house[n].room, &house[n].bathroom, &house[n].carpark,
            house[n].type, house[n].furnish, eol) == 9) {
            n++;
        } else {
            fprintf(stderr, "%s:%d: invalid record: %s\n", "data.csv", lineno, buffer);
        }
    }

    fclose(file);

    for (int i = 0; i < n; i++) {
        printf("%s,%s,%d,%d,%d,%d,%s,%s\n",
               house[i].location, house[i].city, house[i].price,
               house[i].room, house[i].bathroom, house[i].carpark,
               house[i].type, house[i].furnish);
    }

    free((house);
    return 0;
}

字符串
你链接到一个无法访问的屏幕截图,该截图应该只显示从2931到结尾的行(3939行?)。可能的解释很简单:该程序非常快,输出速度如此之快,以至于您只能有机会看到最后一行,所有之前的行都从顶部滚动,使用scroolbars(如果有的话)尝试查看以前的输出,或者将程序传输到head以获取前几行输出,或者将程序传输到more以浏览输出,或wc来计数输出行。

相关问题