【问题标题】:C -- file input reading issueC -- 文件输入读取问题
【发布时间】:2014-03-17 00:06:44
【问题描述】:

我正在从一个文件 emp 中读取,它正在读取文件(这是下面的最后一个文件——它工作)被构造为 10 个带有标题的记录(被 fseek() 跳过代码中的 0)。但是,当它以 3x10 格式(这是下面的中间文件,无法正确读取)读取每个 3 块的标题时——那就失败了。我不确定为什么循环中的条件没有捕获,循环中的第二个条件没有打印前面标记为 0 的所有内容。

    int   nDeleteSwitch;
    char  sSSN[10], sName[21];
    float nSalary;
    char nextIn[3];

    printf("SSN        NAME                 SALARY\n");

    mioHashFile = fopen("emp", "r");
    fscanf (mioHashFile,"%d",&mnOverFlowRecords);
    fseek (mioHashFile, mnHeaderSize, 0); //Skip past the CRLF at end of overflow counter

    //int numHeadRec = mnOverFlowRecords/3;
    /* sequentially print all active records */
    //for(int i=0;i<(numHeadRec+mnOverFlowRecords);i++)
    for(int i=0;i<20+mnOverFlowRecords;i++)
    {
        if ((fscanf(mioHashFile,"%d",nextIn)== -1) || (fscanf(mioHashFile,"%d",nextIn)== 0) ||
            (fscanf(mioHashFile,"%d",nextIn)== 1))
        {
            fscanf(mioHashFile,"%d%s%s%f",&nDeleteSwitch,sSSN,sName,&nSalary);
            //printf("%d",nDeleteSwitch);
            if (nDeleteSwitch==0)printf("%-11s%-21s%-10.2f\n",sSSN,sName,nSalary);  // wtf why this isn't printing 
            else if (nDeleteSwitch == -1) printf("there's a -1 on row: %d",i);
        }
        else {continue;};
    }
        fclose(mioHashFile);
        printf("Print Table Complete\n");

这里有 emp 文件,它拒绝从以下位置读取 0 条目:

   0
Overflow page: 0 0 -1 
 -1         x                    x      0.00
 -1         x                    x      0.00
  0         x                    x      0.00
Overflow page: 1 0 -1 
 -1         x                    x      0.00
 -1         x                    x      0.00
  0         x                    x      0.00
Overflow page: 2 0 -1 
 -1         x                    x      0.00
 -1         x                    x      0.00
 -1         x                    x      0.00
Overflow page: 3 0 -1 
 -1         x                    x      0.00
 -1         x                    x      0.00
 -1         x                    x      0.00
Overflow page: 4 0 -1 
 -1         x                    x      0.00
 -1         x                    x      0.00
 -1         x                    x      0.00
Overflow page: 5 0 -1 
 -1         x                    x      0.00
 -1         x                    x      0.00
 -1         x                    x      0.00
Overflow page: 6 0 -1 
 -1         x                    x      0.00
 -1         x                    x      0.00
 -1         x                    x      0.00
Overflow page: 7 0 -1 
 -1         x                    x      0.00
 -1         x                    x      0.00
 -1         x                    x      0.00
Overflow page: 8 0 -1 
 -1         x                    x      0.00
 -1         x                    x      0.00
 -1         x                    x      0.00
Overflow page: 9 0 -1 
 -1         x                    x      0.00
 -1         x                    x      0.00
 -1         x                    x      0.00

所以它不会读那个,但它会读这个:

   0
  0       123                  asd    789.00
 -1         x                    x      0.00
 -1         x                    x      0.00
 -1         x                    x      0.00
 -1         x                    x      0.00
 -1         x                    x      0.00
  0       345                  zxc    234.00
 -1         x                    x      0.00
 -1         x                    x      0.00
 -1         x                    x      0.00

-1 之前有一个空格,0 之前有 2 个空格。如代码所示,我尝试打印开头为 0 的任何内容,并跳过“标题”行在每个哈希块的前面。当我试图强制它打印时(比如 print

它应该做的是打印所有以0开头的记录并跳过标题(因为它们的开头没有-1,0,1)。

【问题讨论】:

    标签: c file-io string-formatting scanf


    【解决方案1】:

    鉴于声明:

    char nextIn[3];
    

    这段代码是错误的:

    if ((fscanf(mioHashFile,"%d",nextIn) == -1) || (fscanf(mioHashFile,"%d",nextIn) == 0) ||
        (fscanf(mioHashFile,"%d",nextIn) == 1))
        {
    

    您正在传递一个包含三个字符的数组,并期望 fscanf() 将其视为 int。你的条件也很奇怪。 EOF 不能保证是-1(尽管我不记得有一个系统不是这样)。在检测到 EOF 后再次尝试没有多大意义(不是没有其他活动来清除 EOF 标记)。

    当我尝试这个fscanf(mioHashFile,"%s",nextIn); if (strcmp(nextIn, '-1') == 0) 时,由于类型不兼容,它仍然会崩溃并烧毁。 @Emmet 还发现了我在 EOF 上的错误(在那个答案的代码中)。你会怎么做,并且仍然保持我尝试使用的scanf()printf() 格式?

    这需要一些半真实的编码。我会使用fgets()sscanf() 而不是fscanf()

    char line[4096];
    int lineno = 0;
    while (fgets(line, sizeof(line), mioHashFile) != 0)
    {
        if (++lineno == 1)
            continue;  // Skip the offset line
        if (line[0] == 'O') // Overflow line - skip
            continue;
        if (sscanf(line, "%d %9s %20s %f", &nDeleteSwitch, sSSN, sName, &nSalary) != 4)
        {
            fprintf(stderr, "Failed to scan data from: %s", line);
            continue;
        }
        if (nDeleteSwitch == 0)
            printf("%-11s%-21s%-10.2f\n", sSSN, sName, nSalary);
        else if (nDeleteSwitch == -1)
            printf("there's a -1 on row: %d\n", lineno);
        else
            printf("The delete switch value is %d\n", nDeleteSwitch);
    }
    

    请注意,%s 会跳过前导空格,然后在下一个空格处停止扫描。

    【讨论】:

    • 有趣。当我尝试这个fscanf(mioHashFile,"%s",nextIn); if (strcmp(nextIn, '-1') == 0) 时,由于类型不兼容,它仍然会崩溃并烧毁。 @Emmet 还发现了我在 EOF 上的错误(在那个答案的代码中)。您将如何做到这一点,并且仍然保持我尝试使用的 scanf(), printf() 格式?
    • 我非常喜欢半真实编码,所以 +1。我的问题是if (line[0] == 'O') // Overflow line - skip continue; if (sscanf(line, "%d %9s %20s %f", &amp;nDeleteSwitch, sSSN, sName, &amp;nSalary) != 4) { fprintf(stderr, "Failed to scan data from: %s", line); continue; } 这两个条件是多余的吗?我的意思是,这是我对 if &lt;input character at 0&gt; == 'O' 的意图,以避免那些标题记录。
    • 我不认为'O' 条件是可选的,尽管它取决于你的观点。如果您认为!= 4 条件就足够了(因此您不会区分溢出线和故障数据线),那么'O' 条件是可选的。我宁愿单独报告问题。我不确定您在哪里扫描'O'!= 4 条件是至关重要的;如果你不测试sscanf() 是否达到了你的预期,你迟早会崩溃和燃烧。始终检查您是否从任何scanf() 系列函数中获得了正确的返回值。
    • 并注意条件是!= 4,测试除预期数字之外的任何内容。您可能会得到 0、1、2 或 3 以及 sscanf() 返回的 EOF——所有这些都表明存在某种问题。 fgets()sscanf() 方法的一个(主要)优点是您可以报告导致问题的整条生产线,而不仅仅是fscanf() 屠宰生产线的第一部分后剩下的部分。它使错误报告和恢复更容易。
    【解决方案2】:

    您提供的几乎所有细节似乎与您声明的打印以零开头的行而不打印其他行的目标无关。例如,下面的程序打印出所有以零开头的行,但不打印其他行。

    #include <stdio.h>
    #include <stdlib.h>
    
    #define BUF_SZ (512)
    #define INFILE "datafile.txt"
    
    int main(void) {
        char    buf[BUF_SZ] = {0};
        FILE   *fp;
        long    first;
        char   *endp;
    
        /* Open input file successfully or bail */
        fp = fopen(INFILE, "r");
        if( fp == NULL ) {
            fprintf(stderr, "Failed to open '%s'\n", INFILE);
            exit(EXIT_FAILURE);
        }
    
        /* Read each line, convert beginning to long and print if it's 0 */
        while( NULL!=fgets(buf, BUF_SZ, fp) && !feof(fp) ) {
            first = strtol(buf, &endp, 10);
            if( first==0L && endp!=buf ) {
                fputs(buf, stdout);
            }
        }
    
        fclose(fp);
        return 0;
    }
    

    【讨论】:

    • 太棒了。但是,fscanf(mioHashFile,"%d%s%s%f",&amp;nDeleteSwitch,sSSN,sName,&amp;nSalary); printf("%-11s%-21s%-10.2f\n",sSSN,sName,nSalary); 是我发布的格式和我需要的格式。尝试使用它而不是您的fputs(),但我得到了邪恶的垃圾输出。我怎样才能让我的scanf()printf() 去做必须做的事情? #define 文件名的好主意,但是,我在程序中使用了无数次,应该想到这一点。 +1
    • 你怎么知道“ssn”在哪里结束,“name”从哪里开始?在您的示例文件中,没有可区分的分隔符。是否是“固定字符”,即每行上的某些固定范围对应于每个字段。数字(11、21 等)表明了这一点,但我不能确定。
    • 固定是什么意思? (11,21,etc) 是每行输入之间的空格格式,没有\t 或其他。 scanf() 只是通过intchar 拉进来,以该顺序中的预期为准。就像我说的那样,当文件格式像最后一个文件时它可以工作,但随后发生了一些神秘的事情。
    • 我的意思是,似乎每行的字符 1-3 是初始整数,然后总是一个空格,然后 5 到 13(包括 5 到 13)是 SSN,等等。显示的“x”位于显示它的那些字段的最后位置。对吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-07
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 2016-07-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多