【问题标题】:reading,parsing a csv file , populating a struct and then write struct to a data file读取、解析 csv 文件、填充结构然后将结构写入数据文件
【发布时间】:2011-04-02 05:23:37
【问题描述】:

我正在编写一个程序,它读取和解析 CSV 文件,用 CSV 文件的内容填充结构,然后以二进制模式将结构写入文件。我正在解析 csv 文件,方法是对其进行标记并将每个标记写入结构。 问题是当我尝试将此结构写入数据文件时,文件内容显示一些特殊字符,即它写入任何随机值。我附上了我的 output.dat 文件。 谁能帮我找到我错的地方?谢谢。

这是我的代码:

typedef struct  
{
    int AccountNumber;  
    char    *AccountName;  
    double  AccountBalance;  
    double  LastPaymentAmount;  
    char    *LastPaymentDate;  
} Person;

FILE    *fpData;        

Person temp = {0,"",0,0,0};

if ( ( fpData = fopen( "input.csv", "r" ) ) == NULL ) //Reading a file
{
    printf( "File could not be opened.\n" );
}

while(fgets(buf, BUFFER_SIZE, fpData) != NULL)
{
    /* Here we tokenize our string and scan for " \n" characters */

    // for(tok = strtok(buf,"\n");tok;tok=strtok(NULL,"\n"))
    // {
        tok = strtok(buf, ",");
        temp.AccountNumber = atoi(tok); 
        printf(" %i ",temp.AccountNumber );

        tok = strtok(NULL, ",");

        temp.AccountName = tok;
        printf("%s ",temp.AccountName );

        tok = strtok(NULL, ",");

        temp.AccountBalance = atof(tok);
        printf("temp.AccountBalance = %f ",temp.AccountBalance );

        tok = strtok(NULL, ",");

        temp.LastPaymentAmount = atof(tok);
        printf("temp.LastPaymentAmount = %f ",temp.LastPaymentAmount );

        tok = strtok(NULL, ",");

        temp.LastPaymentDate = tok;  
        printf("temp.LastPaymentDate = %s ",temp.LastPaymentDate );

        tok = strtok(NULL, ",");
        printf("\n");                 
    // }  
}

if ( ( fpData = fopen( "output.dat", "wb" ) ) == NULL )  
{  
   printf( "File could not be opened.\n" );  
}  
else  
{  
    printf("\nFileName is:%s\n",argv[2]);  
    printf("File will be overwritten. Do you want to continue?\nPress Y if yes, N if no");  
    printf("\n?\n");  
    scanf("%c", &choice);  

    if(choice=='Y')         
    {  
        for(i=0;i<10;i++)  
        {  
            fwrite(&temp, sizeof(temp), 10, fpData);  
        }           
    }  
}  

fclose(fpData);

【问题讨论】:

  • 你似乎遗漏了一些代码...... 1)你只分配了Person的一个实例,即堆栈上的变量temp——不应该有一个数组还是某种类型的内存指针,指向堆上的Person 结构数组,您将从文件中读取的每个内容保存到其中? 2)buf的分配在哪里,BUFFER_SIZE的定义是什么? 3)我假设您的所有调试信息都正确打印出来(即,您实际上正确标记了文件)?
  • 是的。标记化正在使用 CSV 文件中的 10 个条目正确填充结构。但是当我将其写入文件时,它只会使用一些特殊字符写入最后一个条目。
  • 请注意,RFC 4180 为 CVS 提供了一个比您的分词器处理的更复杂的定义。如果保证输入是您的代码期望的简单形式,那不是灾难,但如果您将从符合 RFC 4180 的源接收数据,则可能会出现问题。见this recent question

标签: c file-io struct


【解决方案1】:

您没有为尝试复制到输出文件的结构数组以及结构中的字符数组成员分配任何内存。简单地复制从strtok() 返回的指针将不起作用,因为它指向strtok() 函数内的静态字符数组。所以基本上在通过你的while循环后,temp.AccountNametemp.LastPaymentDate 都指向同一个确切的内存位置。此外,正如上面 chemuduguntar 所指出的,当您写出结构时,您只是在写出内存指针......您的结构中没有实际的 string data 用于您假设的内容字符数组。

您有两个选择...要么使用静态存储声明您的结构来存储字符串数组,然后使用 strcpy() 将数据从 strtok() 复制到这些数组中,或者使用 malloc() 并为您的指针(请记住,除非您想要内存泄漏,否则以后必须释放这些指针)。

例如,您可以这样做:

#define MAXBUFSIZE 511

typedef struct  
{
    int AccountNumber;  
    char AccountName[MAXBUFSIZE + 1];  
    double AccountBalance;  
    double LastPaymentAmount;  
    char LastPaymentDate[MAXBUFSIZE + 1];  
} Person;

然后在您的 while 循环中,当您调用 strtok() 时,您可以这样做:

tok = strtok(NULL, ",");
strncopy(temp.AccountName, tok, MAXBUFSIZE);
temp.AccountName[MAXBUFSIZE] = '\0'; //safety NULL termination

//...more code

tok = strtok(NULL, ",");
strncopy(temp.LastPaymentDate, tok, MAXBUFSIZE);
temp.LastPaymentDate[MAXBUFSIZE] = '\0'; //safety NULL termination

现在使用这种方法,结构中的实际数据并没有指向某个临时存储空间……这种方法的唯一缺点是,如果超过 512 字节,那么您将剪切该数据。如果小于 512 字节,那么字符数组的末尾将全部填充零。

接下来,您需要在某处声明:

Person myarray[10];

Person* myarray = calloc(10, sizeof(Person));

因为现在每次执行 while 循环时,都会覆盖之前的 temp 值。因此,在某些时候,您需要将 temp 结构复制到更永久的存储阵列中。例如,在您的 while 循环结束时,您应该调用:

memcpy(&myarray[LOOPNUMBER], &temp, sizeof(Person)); 

最后,对于 fwrite() 的调用,我会稍微改变一下,如下所示:

for(i=0;i<10;i++)  
{  
    fwrite(myarray, sizeof(Person), 10, fpData);  
} 

同样,如果您将指针与 malloc()calloc() 等一起使用,请务必在之后调用 free() 释放该存储空间。

希望这会有所帮助,

杰森

【讨论】:

    【解决方案2】:

    如果不在结构中定义用于存储字符串的静态数组,我认为这将无法正常工作,目前当您将结构写入磁盘时 - 仅写入指针。

    【讨论】:

    • 谢谢。但是您能帮我将结构写入文件吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-28
    • 2016-01-26
    • 2013-12-11
    • 2016-09-04
    • 2013-12-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多