首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在C中使用读取文件时遇到的问题

在C中使用读取文件时遇到的问题
EN

Stack Overflow用户
提问于 2022-05-15 14:10:25
回答 2查看 257关注 0票数 0

我编写了下面的代码来将文件读入结构中,但是当我运行这段代码时,输出可以在下面的文本中看到。我想把这个文件读入结构中,每一个字符块都有数字、名字、姓氏等。原始文件也如下所示。

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
struct StudentInfo{
    char studentNumber[20];
    char studentName[20];
    char studentSurname[20];
    char department[20];
    char eMail[20];
};
int main(int argc, char *argv[]) {
    
    //Declarations
    char firstFileName[20];
    char secondFileName[20];
    char operationType[2];
    char data[100];
    struct StudentInfo *studentInfo=(struct StudentInfo*) malloc(sizeof(struct StudentInfo));
    FILE *firstFile;
    FILE *secondFile;
    printf("Enter the first file name: ");
    scanf("%s",firstFileName);
    printf("Enter the second file name: ");
    scanf("%s",secondFileName);
    printf("Enter the operation type (-i, -u):");
    scanf("%s",operationType);
    
    if(strcmp(operationType,"-i")==0){
    
        firstFile = fopen(strcat(firstFileName,".txt"),"r");
        while(!feof(firstFile)){
            fread(studentInfo,sizeof(struct StudentInfo),1,firstFile);
            printf("%s",studentInfo->studentNumber);
        }
    }
    if(strcmp(operationType,"-u")==0){
        printf("%s",secondFileName);    
    }
    fclose(firstFile);

    /*
    while(!feof(firstFile)){
        students[1]->studentNumber = 
    }
    fclose(firstFile);*/
    
}

文件的原始内容是:

代码语言:javascript
复制
Ogrenci No;Ogrenci;Program;Sinif;Email;Status
10000000000;EDA NUR   YILMAZ;Computer Engineering;4;enur.yilmaz@tedu.edu.tr;
10000000010;FEYZA  NUR  DUMAN;Computer Engineering;2;fnur.duman@tedu.edu.tr;
20000000010;GOKHAN  YAMAC;Computer Engineering;2;gokhan.yamac@tedu.edu.tr;
30000000030;CEREN  AYDINLI;Computer Engineering;2;ceren.aydinli@tedu.edu.tr;
30000000010;DURU  YAMAC;Computer Engineering;3;duru.yamac@tedu.edu.tr;
40000000010;SEVIL TERZI;Computer Engineering;2;sevil.terzi@tedu.edu.tr;
50000000010;EREN  AYDIN;Computer Engineering;2;eren.aydin@tedu.edu.tr;
50000000020;YAMAC    YILMAZ;Computer Engineering;2;yamac.yilmaz@tedu.edu.tr;
60000000020;EDANUR    YILMAZ;Computer Engineering;2;edanur.yilmaz@tedu.edu.tr;
70000000010;GOKHAN YAMAC;Computer Engineering;2;gokhan.yamac18@tedu.edu.tr;

我代码的输出是:

代码语言:javascript
复制
Ogrenci No;Ogrenci;Program;Sinif;Email;Status
10000000000;EDA NUR   YILMAZ;Computer Engineering;4;enPI_K³Æ_aj©ur.yilmaz@tedu.edu.tr;
10000000010;FEYZA  NUR  DUMAN;Computer Engineering;2;fnur.duman@tedu.edu.tr;
PI_K³Æ_aj©20000000010;GOKHAN  YAMAC;Computer Engineering;2;gokhan.yamac@tedu.edu.tr;
30000000030;CEREN  AYDINLPI_K³Æ_aj©I;Computer Engineering;2;ceren.aydinli@tedu.edu.tr;
30000000010;DURU  YAMAC;Computer Engineering;3;dPI_K³Æ_aj©uru.yamac@tedu.edu.tr;
40000000010;SEVIL TERZI;Computer Engineering;2;sevil.terzi@tedu.edu.tr;
50000PI_K³Æ_aj©000010;EREN  AYDIN;Computer Engineering;2;eren.aydin@tedu.edu.tr;
50000000020;YAMAC    YILMAZ;ComputPI_K³Æ_aj©er Engineering;2;yamac.yilmaz@tedu.edu.tr;
60000000020;EDANUR    YILMAZ;Computer Engineering;2;edanuPI_K³Æ_aj©r.yilmaz@tedu.edu.tr;
70000000010;GOKHAN YAMAC;Computer Engineering;2;gokhan.yamac18@tedu.edu.tr;
nuPI_K³Æ_aj©
EN

回答 2

Stack Overflow用户

发布于 2022-05-15 17:57:10

环路

代码语言:javascript
复制
while(!feof(firstFile)){
    fread(studentInfo,sizeof(struct StudentInfo),1,firstFile);
    printf("%s",studentInfo->studentNumber);
}

是错误的,有几个原因:

循环条件是错误的。有关更多信息,请参见以下问题:Why is “while ( !feof (file) )” always wrong?

线

代码语言:javascript
复制
fread(studentInfo,sizeof(struct StudentInfo),1,firstFile);

将尝试从文件中准确读取sizeof(struct StudentInfo)字节,即100个字节。换句话说,你的程序假设每一行都是100字节长,下一个条目也就是100字节长。您的程序还假设这100字节长的条目之间没有任何内容(也没有换行符)。此外,您的程序假设文件中的每个字符串中都有一个空终止字符(因为稍后您试图将它们打印为空终止字符串)。所有这三个假设都是错误的。

您实际拥有的是一个文件,其中每个条目由换行符分隔。条目的字段具有可变长度(而不是固定长度为20),这些字段由;字符分隔。因此,使用函数fgets一次读取一行比较合适,并使用strtok将该行划分为单独的字段:

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct StudentInfo
{
    char studentNumber[20];
    char studentName[20];
    char department[20];
    char unknown[20];
    char eMail[20];
};

int main( void )
{
    FILE *fpInput;
    char line[400];
    struct StudentInfo si;

    //open input file
    fpInput = fopen( "input.txt", "r" );
    if ( fpInput == NULL )
    {
        fprintf( stderr, "Error opening file!\n" );
        exit( EXIT_FAILURE );
    }

    //ignore first line of input
    fgets( line, sizeof line, fpInput );

    //read one line of input per loop iteration
    while ( fgets( line, sizeof line, fpInput ) != NULL )
    {
        char *p;

        //attempt to find newline character
        p = strchr( line, '\n' );

        //make sure entire line was read, and remove newline
        //character if necessary
        if ( p == NULL )
        {
            //a missing newline character is ok on end-of-file
            if ( !feof(fpInput) )
            {
                fprintf( stderr, "Line too long for input buffer!\n" );
                exit( EXIT_FAILURE );
            }
        }
        else
        {
            //remove newline character from input
            *p = '\0';
        }

        //attempt to read student number
        p = strtok( line, ";" );
        if ( p == NULL )
        {
            fprintf( stderr, "Unable to find student number!\n" );
            exit( EXIT_FAILURE );
        }

        //attempt to copy student number to struct
        if ( snprintf( si.studentNumber, sizeof si.studentNumber, "%s", p ) >= (int)(sizeof si.studentNumber) )
        {
            fprintf( stderr, "Not enough space to copy student number.\n" );
            exit( EXIT_FAILURE );
        }

        //attempt to read student name
        p = strtok( NULL, ";" );
        if ( p == NULL )
        {
            fprintf( stderr, "Unable to find student name!\n" );
            exit( EXIT_FAILURE );
        }

        //attempt to copy student name to struct
        if ( snprintf( si.studentName, sizeof si.studentName, "%s", p ) >= (int)(sizeof si.studentName) )
        {
            fprintf( stderr, "Not enough space to copy student name.\n" );
            exit( EXIT_FAILURE );
        }

        //attempt to read department
        p = strtok( NULL, ";" );
        if ( p == NULL )
        {
            fprintf( stderr, "Unable to find department!\n" );
            exit( EXIT_FAILURE );
        }

        //attempt to copy department to struct
        if ( snprintf( si.department, sizeof si.department, "%s", p ) >= (int)(sizeof si.department) )
        {
            fprintf( stderr, "Not enough space to copy department.\n" );
            exit( EXIT_FAILURE );
        }

        //attempt to read unknown field
        p = strtok( NULL, ";" );
        if ( p == NULL )
        {
            fprintf( stderr, "Unable to find unknown field!\n" );
            exit( EXIT_FAILURE );
        }

        //attempt to copy unknown field to struct
        if ( snprintf( si.unknown, sizeof si.unknown, "%s", p ) >= (int)(sizeof si.unknown) )
        {
            fprintf( stderr, "Not enough space to copy unknown field.\n" );
            exit( EXIT_FAILURE );
        }

        //attempt to read email
        p = strtok( NULL, ";" );
        if ( p == NULL )
        {
            fprintf( stderr, "Unable to find email!\n" );
            exit( EXIT_FAILURE );
        }

        //attempt to copy email to struct
        if ( snprintf( si.eMail, sizeof si.eMail, "%s", p ) >= (int)(sizeof si.eMail) )
        {
            fprintf( stderr, "Not enough space to copy eMail.\n" );
            exit( EXIT_FAILURE );
        }

        //print data from struct
        printf(
            "Successfully read the following student entry:\n"
            "Number    : %s\n"
            "Name      : %s\n"
            "Department: %s\n"
            "Unknown   : %s\n"
            "E-Mail    : %s\n"
            "\n",
            si.studentNumber, si.studentName, si.department,
            si.unknown, si.eMail
        );
    }
}

由于您还没有回应我要求澄清输入字段中第四个字段的含义的要求,我只是简单地在stuct StudentInfo中将其标记为“未知”。

但是,当我运行这个程序时,我会收到以下错误消息:

代码语言:javascript
复制
Not enough space to copy department.

这是因为您对struct StudentInfo的定义包含以下行:

代码语言:javascript
复制
char department[20];

这意味着它只能存储19字符加上终止空字符。但是,在输入文件中,您有Computer Engineering,它是20字符long (21包括终止空字符)。因此,必须将数组的大小至少增加到21

你也有同样的问题

代码语言:javascript
复制
char eMail[20];

此数组不足以存储字符串。

代码语言:javascript
复制
enur.yilmaz@tedu.edu.tr

因为它需要24个字符(包括终止字符)

在将两个数组的大小从20增加到30之后,程序就可以工作了。它将有以下输出:

代码语言:javascript
复制
Successfully read the following student entry:
Number    : 10000000000
Name      : EDA NUR   YILMAZ
Department: Computer Engineering
Unknown   : 4
E-Mail    : enur.yilmaz@tedu.edu.tr

Successfully read the following student entry:
Number    : 10000000010
Name      : FEYZA  NUR  DUMAN
Department: Computer Engineering
Unknown   : 2
E-Mail    : fnur.duman@tedu.edu.tr

Successfully read the following student entry:
Number    : 20000000010
Name      : GOKHAN  YAMAC
Department: Computer Engineering
Unknown   : 2
E-Mail    : gokhan.yamac@tedu.edu.tr

Successfully read the following student entry:
Number    : 30000000030
Name      : CEREN  AYDINLI
Department: Computer Engineering
Unknown   : 2
E-Mail    : ceren.aydinli@tedu.edu.tr

Successfully read the following student entry:
Number    : 30000000010
Name      : DURU  YAMAC
Department: Computer Engineering
Unknown   : 3
E-Mail    : duru.yamac@tedu.edu.tr

Successfully read the following student entry:
Number    : 40000000010
Name      : SEVIL TERZI
Department: Computer Engineering
Unknown   : 2
E-Mail    : sevil.terzi@tedu.edu.tr

Successfully read the following student entry:
Number    : 50000000010
Name      : EREN  AYDIN
Department: Computer Engineering
Unknown   : 2
E-Mail    : eren.aydin@tedu.edu.tr

Successfully read the following student entry:
Number    : 50000000020
Name      : YAMAC    YILMAZ
Department: Computer Engineering
Unknown   : 2
E-Mail    : yamac.yilmaz@tedu.edu.tr

Successfully read the following student entry:
Number    : 60000000020
Name      : EDANUR    YILMAZ
Department: Computer Engineering
Unknown   : 2
E-Mail    : edanur.yilmaz@tedu.edu.tr

Successfully read the following student entry:
Number    : 70000000010
Name      : GOKHAN YAMAC
Department: Computer Engineering
Unknown   : 2
E-Mail    : gokhan.yamac18@tedu.edu.tr

但是,这个解决方案不太好的一点是,它包含大量的代码重复。处理所有5个字段的代码几乎是相同的,所以最好统一此代码:

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct StudentInfo
{
    char studentNumber[20];
    char studentName[20];
    char department[30];
    char unknown[20];
    char eMail[30];
};

int main( void )
{
    FILE *fpInput;
    char line[400];
    struct StudentInfo si;

    struct field
    {
        char *p_str;
        size_t size;
    };

    //arrange fields in an array, so that it can be used in
    //a loop
    struct field fields[] = {
        { si.studentNumber, sizeof si.studentNumber },
        { si.studentName,   sizeof si.studentName },
        { si.department,    sizeof si.department },
        { si.unknown,       sizeof si.unknown },
        { si.eMail,         sizeof si.eMail }
    };

    //open input file
    fpInput = fopen( "input.txt", "r" );
    if ( fpInput == NULL )
    {
        fprintf( stderr, "Error opening file!\n" );
        exit( EXIT_FAILURE );
    }

    //ignore first line of input
    fgets( line, sizeof line, fpInput );

    //read one line of input per loop iteration
    while ( fgets( line, sizeof line, fpInput ) != NULL )
    {
        char *p;

        //attempt to find newline character
        p = strchr( line, '\n' );

        //make sure entire line was read, and remove newline
        //character if necessary
        if ( p == NULL )
        {
            //a missing newline character is ok on end-of-file
            if ( !feof(fpInput) )
            {
                fprintf( stderr, "Line too long for input buffer!\n" );
                exit( EXIT_FAILURE );
            }
        }
        else
        {
            //remove newline character from input
            *p = '\0';
        }

        p = strtok( line, ";" );

        for ( size_t i = 0; i < sizeof fields / sizeof *fields; i++ )
        {
            //verify that field exists
            if ( p == NULL )
            {
                fprintf( stderr, "Unable to find student number!\n" );
                exit( EXIT_FAILURE );
            }

            //attempt to copy field to struct
            if ( snprintf( fields[i].p_str, fields[i].size, "%s", p ) >= (int)(fields[i].size) )
            {
                fprintf( stderr, "Not enough space to copy field.\n" );
                exit( EXIT_FAILURE );
            }

            p = strtok( NULL, ";" );
        }

        //print data from struct
        printf(
            "Successfully read the following student entry:\n"
            "Number    : %s\n"
            "Name      : %s\n"
            "Department: %s\n"
            "Unknown   : %s\n"
            "E-Mail    : %s\n"
            "\n",
            si.studentNumber, si.studentName, si.department,
            si.unknown, si.eMail
        );
    }
}
票数 1
EN

Stack Overflow用户

发布于 2022-05-15 22:34:15

您的代码出现了许多问题:

  • char operationType[2];只能容纳一个字符(另一个是因为\0);
  • struct StudentInfo *studentInfo=(struct StudentInfo*) malloc(sizeof(struct StudentInfo));太不必要了,long;
  • while(!feof(firstFile))always wrong;
  • You误用了,scanf;
  • You没有检查fopen的返回值,fread;
  • The格式的文件暗示它是带有头的csv。在您的示例中,fread不是将您的文件读入struct StudentInfo的正确方法。appropriate.

更多的是fgets

@Andreas Wenzel已经提供了a solution。下面是使用sscanf的另一个版本

首先,重新定义您的结构,这样就更有意义了:

代码语言:javascript
复制
struct StudentInfo {
    char studentNumber[12];
    char studentName[50];
    char department[50];
    int weired;  // What is this?
    char eMail[50];
};

其次,定义一个从输入流读取一行的函数:

代码语言:javascript
复制
char *read_line(char *line, size_t size, FILE *stream)
{
    if(!fgets(line, size, stream))
        return NULL;
    
    size_t npos = strcspn(line, "\n");
    line[npos] = '\0';
    return line;
}

然后将其与sscanf结合使用

代码语言:javascript
复制
int main(int argc, const char *argv[])
{
    const char *filename = "file.txt";
    
    FILE *file = fopen(filename, "r");
    if (!file) {
        fprintf(stderr, "Could not open file %s\n", filename);
        exit(EXIT_FAILURE);
    }
    
    char line[1024]; // 1KB should be large enough
    struct StudentInfo students[100];
    size_t nstudents = 0;
    
    // Read and discard the first line
    read_line(line, sizeof line, file);
    
    // Read the rest of the file
    for (size_t lineno = 0; read_line(line, sizeof line, file); ++lineno) {
        char studentNumber[12];
        char studentName[50];
        char department[50];
        int weired;
        char eMail[50];
        
        int ret = sscanf(line, " %11[^;\n];%49[^;\n];%49[^;\n];%d;%49[^;\n];", studentNumber, studentName, department, &weired, eMail);
        
        if (ret != 5) {
            printf("> [ERROR] on line %ld: expected %d fields, but only parsed %d\n", lineno, 5, ret);
            continue;
        }
        
        // Copy data to struct array only when parsing succeeded
        
        struct StudentInfo *st = &students[nstudents++];
        strncpy(st->studentNumber, studentNumber, sizeof(studentNumber));
        strncpy(st->studentName, studentName, sizeof(studentName));
        strncpy(st->department, department, sizeof(department));
        st->weired = weired;
        strncpy(st->eMail, eMail, sizeof(eMail));
        
        //printf("%s\n%s\n%s\n%d\n%s\n\n", studentNumber, studentName, department, weired, eMail);
    }
    
    fclose(file);
    
    for (size_t i = 0; i < nstudents; ++i) {
        struct StudentInfo *st = &students[i];
        printf("Student #%ld\n", i+1);
        printf("%s\n%s\n%s\n%d\n%s\n\n", st->studentNumber, st->studentName, st->department, st->weired, st->eMail);
    }
}

在这里,%11[^;\n];部分的意思是“读取所有内容,直到找到换行符或分号,或者达到11个字符的最大限制,然后读取分号。”

输出:

代码语言:javascript
复制
Student #1
10000000000
EDA NUR   YILMAZ
Computer Engineering
4
enur.yilmaz@tedu.edu.tr

Student #2
10000000010
FEYZA  NUR  DUMAN
Computer Engineering
2
fnur.duman@tedu.edu.tr

Student #3
20000000010
GOKHAN  YAMAC
Computer Engineering
2
gokhan.yamac@tedu.edu.tr

Student #4
30000000030
CEREN  AYDINLI
Computer Engineering
2
ceren.aydinli@tedu.edu.tr

Student #5
30000000010
DURU  YAMAC
Computer Engineering
3
duru.yamac@tedu.edu.tr

Student #6
40000000010
SEVIL TERZI
Computer Engineering
2
sevil.terzi@tedu.edu.tr

Student #7
50000000010
EREN  AYDIN
Computer Engineering
2
eren.aydin@tedu.edu.tr

Student #8
50000000020
YAMAC    YILMAZ
Computer Engineering
2
yamac.yilmaz@tedu.edu.tr

Student #9
60000000020
EDANUR    YILMAZ
Computer Engineering
2
edanur.yilmaz@tedu.edu.tr

Student #10
70000000010
GOKHAN YAMAC
Computer Engineering
2
gokhan.yamac18@tedu.edu.tr
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72249036

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档