如何读取不确定的数据表单文件并将其存储在struct中

时间:2015-04-28 13:52:04

标签: c

我无法从文件中读取数据。

文件:

0   0.0
0   0.0
0   0.0
0   0.0
0   0.0
0   0.0
23 liu zhengzhi 90
0   0.0
0   0.0
0   0.0
0   0.0
0   0.0
0   0.0
0   0.0
0   0.0
0   0.0
0   0.0
0   0.0
0   0.0
0   0.0

在文件中,您不确定一行是0 0.0还是int char* char* double,我需要将其读取到结构中。

结构:

typedef struct Credit
{
    char first_name[20]="";
    char last_name[20]="";
    int account_number=0;
    double balance=0.0;
}account;

我该怎么做。

4 个答案:

答案 0 :(得分:2)

鉴于只有两种情况,解析得以简化:

1) 使用fopen()打开/读取文件
2) 在while循环中使用fgets()逐行读取
3) 使用strtok()标记并存储每个新行的元素(如果是线程,则为strtok_r() 4) 每行使用令牌数,并测试每个字符串令牌的内容
5) 对于2个令牌的计数,跳过行 6) 对于4个令牌的计数,转换为1和1第4串。 (atoi()& atof()
7) 将解析后的值分配给struct成员 8) 关闭文件 - fclose()

如果有可能有超过1个数据行,那么您可能需要一个struct数组来包含数据:

对于您显示的数据文件,这是一个使用这些步骤的非常简单的解析例程示例:

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

typedef struct Credit
{
    char first_name[20];
    char last_name[20];
    int account_number;
    double balance;
}ACCOUNT;

ACCOUNT account[10];

int main()
{
    char file[]={"C:\\Play\\account.txt"};
    char line[1024];
    char *token = {0};
    char delim[]={" \r\n\t"};
    int count, i, j;
    char array[4][80];//should be dynamically allocated, this for illustration

    FILE *fp = fopen(file, "r");
    if(fp)
    {
        j = 0;
        while (fgets(line, 1024, fp) != NULL)
        {
            token = strtok(line, delim);
            i = -1;
            while(token)
            {
                i++;
                strcpy(array[i], token);
                token = strtok(NULL, delim);
            }
            if(i==3)
            {
                account[j].account_number = atoi(array[0]);
                strcpy(account[j].first_name, array[1]);
                strcpy(account[j].last_name, array[2]);
                account[j].balance = atof(array[3]);
            }
            j++;//for next in array of account
            memset(array, 0, 320);
        }
        fclose(fp);
    }

    return 0;

}

答案 1 :(得分:2)

如果需要,可以多次解析字符串。

使用" %n"确定成功。 "%n"指定保存扫描的char个数。由于它是最后一个,因此只有在扫描完成后才会更改。也适用于在线上寻找额外的垃圾。

// Return number of fields successfully scanned 4, 2, 0
int ParseLine(account *dest, const char *src) {
  int n = 0;
  sscanf(src, "%d%19s%19s%lf %n", &dest->account_number, dest->first_name, 
     dest->last_name, &dest->balance, &n);
  // If all fields scanned and no extra garbage ...
  if (n && src[n] == 0) {
    return 4;
  }

  n = 0;
  sscanf(src, "%d%lf %n", &dest->account_number, &dest->balance, &n);
  if (n && src[n] == 0) {
    dest->first_name[0] = dest->last_name[0] = 0;
    return 2;
  }

  return 0; // nothing scanned
}

通过测试更长的名称是否可读,更稳健的测试可确保first/last不超过19 char

  char first[20+1];
  first[19] = 0;
  char last[20+1];
  last[19] = 0;
  sscanf(src, "%d%20s%20s%lf %n", &dest->account_number, first, 
     last, &dest->balance, &n);
  // If all fields scanned, no extra garbage, no long name ...
  if (n && src[n] == 0 && first[19] == 0 && last[19] == 0) {
    strcpy(dest->first_name, first); 
    strcpy(dest->last_name, last); 
    return 4;
  }

代码可以使用"%d %19s %19s %lf %n"代替"%d%19s%19s%lf %n"。它可能更具可读性,但由于"%d""%s""%f"无论如何都会消耗领先的空白区域 - 它没有任何功能差异。

答案 2 :(得分:0)

1。)一种方法。使用getline逐行读取该行。 Read返回一行中的字符数。如果字符数为4,则跳过它,如果它是15,则根据需要将其存储在struct中

while ((read = getline(&line, &len, fp)) != -1) {
       if(read==15)
       {
        //store it in struct
       }
     }

2。)另一种方法是使用字符串标记符,如果标记是4则存储它 结构

有很多方法可以做到这一点。共同基线是一行具有更多字符,而其他行具有相同数量的字符或单词。所以我不打算称这些不确定的数据。它为它设定了模式。

答案 3 :(得分:0)

以下代码,干净地编译,有效 并且是一种读取指定文件的建议方法。

并非所有人都同意使用'continue'

#include <stdio.h>   // fopen, fclose, fgets
#include <stdlib.h>  // exit, EXIT_FAILURE
#include <string.h>  // memset

struct account
{
    char first_name[20];
    char last_name[20];
    int account_number;
    double balance;
};

#define MAX_LINE_LEN (1024)

int main( int argc, char* argv[])
{   
    if( 2 != argc )
    { // then missing file name argument
        printf( "usage: %s <accountFileName>\n", argv[0] );
        exit( EXIT_FAILURE );
    }

    // implied else, correct number of command line arguments

    printf( "processing file: %s\n", arg[1] );

    FILE *fp = NULL;

    if( NULL == (fp = fopen( argv[1], "r" ) ) )
    { // then fopen failed
        perror( "fopen for input file failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, fopen successful

    struct account* accountList = NULL;
    char buffer[MAX_LINE_LEN] = { '\0' };
    int numAccounts = 0;

    while( fgets( buffer, sizeof buffer, fp ) )
    {
        if( '0' == buffer[0] ) // assumes no 'id' starts with 0
        { // then, 'this' record not of interest

            // clear for next loop iteration
            memset( buffer, 0x00, sizeof buffer );
            continue; // go to top of loop and get another record
        }

        // when get here, then record of interest

        // used so realloc failure does not lose pointer to allocated memory
        struct account* temp = NULL;

        if( NULL == (temp = realloc( accountList, sizeof( struct account )*numAccounts+1 ) ) )
        { // then malloc failed
            perror( "realloc failed" );

            printf( "realloc failed for record number: %d\n", numAccounts+1);
            free( accountList );
            fclose( fp );
            exit( EXIT_FAILURE );
        }

        // implied else, malloc successful

        accountList = temp;  // update pointer to allocated memory

        // clear the new account struct area
        memset( &(accountList[numAccounts]), 0x00, sizeof( struct account ) );

        // following assumes all records are properly formatted
        if( 4 != sscanf( buffer, "%d %19s %19s %lf", 
                        &accountList[numAccounts].account_number,
                         accountList[numAccounts].first_name,
                         accountList[numAccounts].last_name,
                        &accountList[numAccounts].balance ) )
        { // then sscanf failed
            perror( "sscanf for record parsing failed" );
            // add error handling here, following is suggested error handling
            printf( "sscanf/record parsing failed for record number: %d\n", numAccounts+1 );
            free( accountList );
            fclose (fp );
            exit( EXIT_FAILURE );
        }

        // implied else, sscanf successful

        // clear for next loop iteration
        memset( buffer, 0x00, sizeof buffer );
    } // end while loop

    // done with file, so close it
    fclose( fp );

    // --add processing of account list here--

    free( accountList );

    return(0);
} // end function: main