简体   繁体   English

从多个文件读入结构

[英]Reading from multiple files into a struct

I am having trouble with an assignment, it involves reading from files into structures and I'm confused on how to do it here is the function with the parameters I HAVE to use. 我在分配时遇到麻烦,它涉及从文件读取到结构中,而我对如何执行此操作感到困惑,这是带有参数的函数。

// This function will read in size  struct players from filename and add these
// the players array. The function will use index  to know where to start
// writing  the players to in the array.
// Parameters
//
// filename – The name of the input file
// players – a pointer to the array of player structures
// index – The index of the array to start placing players into
// size – The number of players in the input file
// Return - Nothing

void read_from_file(char* filename, Player* players, int index, int size);

This is the function I have to use to read in data from 3 DIFFERENT files that look as such: 我必须使用此函数从3个不同的文件中读取数据,这些文件如下所示:

Andrew Jackson 129 33 38 30 506
Jeremy Warden 25 24 3 9 493
Jared Welch 130 1 43 27 422
Brandon Splitter 138 38 40 7 587
Joe Gwilliams 150 23 30 25 498
Ali Mohammed 119 43 13 6 598
Dheeraj Johnson 124 79 59 36 506
Bill Clinton 121 65 12 26 449
Jesse James 87 58 8 5 464
John Doe 129 100 0 12 548

I have to read in 3 files that all have 10 players in them for a total of 30 I need to read into the structures. 我必须读取3个文件,这些文件中都包含10个播放器,总共需要读取30个文件。 I have not gotten very far I know but I am very confused on what to do and how to approach this, any help would be very much appreciated! 我还没走很远,但是我对如何做以及如何做到这一点感到非常困惑,任何帮助将不胜感激! Below I have down what I have already done. 下面是我已经做过的事情。 Please help!! 请帮忙!! Thanks 谢谢

//Brady Webb
//lab D
//HW1

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

typedef struct player
{
    char Fname[25];
    char Lname[25];
    int Singles;
    int Doubles;
    int Triples;
    int Homeruns;
    int At_Bats;
    float Slugging_Percentage;
} Player;

void read_from_file(char* filename, Player* players, int index, int size);

int main(int argc, char* argv[])
{
    int size= atoi(*(argv+1));
    char* file1 = *(argv+2);
    char* file2 = *(argv+3);
    char* file3 = *(argv+4);
    if (argc<6 || argc>6)
    {
        printf("Incorrect command line arguments\n");
        return 0;
    }

    return 0;
}
void read_from_file(char*filename, Player* players, int index, int size)
{
    FILE *ptr;
    int i=0;

    if ((ptr=fopen(filename, "r")) == NULL)
    {
        return 0;
    }

    while (ptr != EOF)
    {

    }

}

The simplest approach to read file with regular structure is to use fscanf with complex format string. 读取具有常规结构的文件的最简单方法是将fscanf与复杂格式的字符串一起使用。

fscanf("%s %s %d %d %d %d %d", Player.Fname, Player.Lname, 
                          &Player.Singles, &Player.Doubles, 
                          &Player.Triples, &Player.Homeruns, &Player.At_Bats);

You should make a loop to read till the and of file, and you can add the check of reading the data in the correct format, eg: 您应该循环读取文件的和,然后可以以正确的格式添加读取数据的检查,例如:

int check = fscanf("%s %s %d %d %d %d %d", Player.Fname, Player.Lname, 
                          &Player.Singles, &Player.Doubles, 
                          &Player.Triples, &Player.Homeruns, &Player.At_Bats);
if( check != 7 )
{
   // stop reading and report on wrong file format 
}

UPDATE: 更新:

I propose the following code as possible solution: 我提出以下代码作为可能的解决方案:

// This function will read in size  struct players from filename and add these
// the players array. The function will use index  to know where to start
// writing  the players to in the array.
// Parameters
//
// filename – The name of the input file
// players – a pointer to the array of player structures
// index – The index of the array to start placing players into
// size – The number of players in the input file
// Return - number of read players (positive number)
//          or error code (negarive number)
int read_from_file(char * filename, Player* players, int index, int size)
{
    struct player ptmp;
    FILE *fptr;
    // open the file
    if ((fptr = fopen(filename, "r")) == NULL)
    {
        fprintf(stderr, "File %s cannot be oppened\n",filename);
        return -1; // error code for "File cannot be oppened"
    }
    // reading from file 
    int position = index;
    int cnt = 0;
    while (!ferror(fptr) && cnt < size)
    {
        int check = fscanf(fptr, "%24s %24s %d %d %d %d %d", ptmp.Fname, ptmp.Lname,
            &ptmp.Singles, &ptmp.Doubles, &ptmp.Triples, &ptmp.Homeruns, &ptmp.At_Bats);
        if (feof(fptr) && check != 7)
        {
            break;
        }
        if (check != 7)
        {
            fclose(fptr);
            fprintf(stderr,"Wrong data format in line %d of file %s\n", cnt+1, filename);
            return -2; // error code for "File has wrong data format"
        }
        // copy data to players
        players[index++] = ptmp;
        cnt++;
    }
    // close the file
    fclose(fptr);
    return cnt;
}

Pay attention at changed type of function read_from_file - I described my idea concerning return value in the comments. 注意函数read_from_file更改类型-我在注释中描述了关于返回值的想法。

And main in my understanding should be like: 根据我的理解, main应该是:

int main(int argc, char* argv[])
{
    Player players[30]; // memory is allocated for particular number of data items
    // check the command line arguments
    if (argc < 3)
    {
        printf("Please run the program in the format:\n");
        printf(" %s 2 firstFile.txt secondFile.txt\n", argv[0]);
        printf(" where 2 is number of files given after 2 with data to be read\n");
        return 0;
    }
    int fileNumber = 0;
    if (!sscanf(argv[1], "%d", &fileNumber) || fileNumber <= 0)
    {
        printf("The first command line argument nust be positive number.\n");
        printf("Run program without parameters to see details\n");
        return 0;
    }
    if (fileNumber != (argc - 2))
    {
        printf("Command line arguments are inconsistent\n");
        printf("Run program without parameters to see details\n");
        return 0;
    }
    // file processing
    int i = 0;
    int total = 0;
    int max = 30;
    for (i = 0; i < fileNumber; i++)
    {
        printf("Reading from %s...\n", argv[i + 2]);
        int res = read_from_file(argv[i + 2], players, total, max); 
        if (res > 0)
        {
            total += res;
            max -= res;
        }
    }
    // check data
    for (i = 0; i < total; i++)
    {
        printf("%s %s : %d %d %d %d %d\n", players[i].Fname, players[i].Lname, players[i].Singles, players[i].Doubles, players[i].Triples, players[i].Homeruns, players[i].At_Bats);
    }
    return 0;
}

It is assumed that 30 players can be read any number of files, and not necessarily to 10 of each file. 假定可以读取30个播放器的任何数量的文件,而不必读取每个文件中的10个文件。

The loop can be return to read one line at a time and each line can be passed to a helper function like getPlayer 该循环可以返回一次读取一行,并且每一行都可以传递给诸如getPlayer的辅助函数。

char *line;
char buffer[256]; // assuming that's the longest line size
while ((line = fgets(buffer, sizeof(buffer), ptr)) != NULL) {
    Player *pl = getPlayer(line);
    //...
}

The above code should replace loop in the code posted as while (ptr != EOF) . 上面的代码应替换while(ptr!= EOF)发布的代码中的循环。 The getPlayer can be something along the following lines (the player can then be added to list/array etc. and make sure you free up accordingly when you are done) getPlayer可以是以下几行(可以将播放器添加到列表/数组等,并确保完成后相应释放)

Player *getPlayer(char *line) {
        Player *iPlayer = (Player *)malloc(sizeof(Player));
        sscanf(line, "%s %s %d %d %d %d %d %f",
                iPlayer->Fname,
                iPlayer->Lname,
                &iPlayer->Singles,
                &iPlayer->Doubles,
                &iPlayer->Triples,
                &iPlayer->Homeruns,
                &iPlayer->At_Bats,
                &iPlayer->Slugging_Percentage);
         return iPlayer;
}
struct Player PlayerArr[10];

void read_from_file(char*filename, Player* players, int index, int size)
{
    FILE *ptr;
    int i=0;
    char content[50];

    memset(content, '\0', 50);

    if ((ptr=fopen(filename, "r")) == NULL)
    {
        return 0;
    }

    while (ptr != EOF)
    {
         getline(infile,line);
         memset(content,'\0',sizeof(content));
         strcpy(content,line.c_str());
         ReadNextConfRecord(content);
    }

    return 0;
}

int ReadNextConfRecord(char *content)
{
        char str[50];
    const char delimiter[2] = " ";
    char *token;
    int count =0;
    int i =0;

    memset(str, '\0', 50);

    strcpy(str, (char*)content);

    token = strtok(str, delimiter);
    while( token != NULL )
    {
     count++;
        if(count == 1)
            {
                strcpy(PlayerArr[i].Fname, token);
            }
        else if(count == 2)
            {
                strcpy(PlayerArr[i].Lname, token);
            }
        else if(count == 3)
            {
                PlayerArr[i].Singles= atoi(token);
            }
        else if(count == 4)
            {
               PlayerArr[i].Doubles= atoi(token);
            }
        else if(count == 5)
            {
               PlayerArr[i].Triples= atoi(token);
            }
        else if(count == 6)
            {
               PlayerArr[i].Homeruns= atoi(token);
            }
        else if(count == 7)
            {
               PlayerArr[i].At_Bats= atoi(token);
            }
        else if(count == 8)
            {
               PlayerArr[i].Slugging_Percentage= atof(token);
            }
       i++;                       
      token = strtok(NULL, delimiter);
    }
    return 0;
}

Using tokenizer can also solve above problem 使用令牌生成器也可以解决上述问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM