我无法从文件中读取数据。
文件:
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;
我该怎么做。
答案 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