简体   繁体   English

程序读取文件,但在不应跳过的行时“跳过”行

[英]Program reads file but “skips” lines when they shouldn't be skipped

So basically I have a program that reads in a specific format of a file as shown: 所以基本上我有一个程序,可以读取文件的特定格式,如下所示:

P3
# CREATOR: GIMP PNM Filter Version 1.1
400 530
255
189
165
181
181
156
...

My program reads in the first line as the format of the file, then any comments starting with a '#', then the width and height, then the max rgb value and then any other rgb values. 我的程序在第一行中读取文件格式,然后以“#”开头的所有注释,然后是宽度和高度,然后是最大rgb值,然后是任何其他rgb值。

NOTE: the part reading in the rgb values is incomplete so ignore this for my question. 注意: rgb值中的零件读取不完整,因此请忽略此问题。 Now to my issue.. 现在到我的问题。

The output i want is as shown as the exact file format, but the result i get is as follows: 我想要的输出显示为确切的文件格式,但是我得到的结果如下:

P3
# CREATOR: GIMP PNM Filter Version 1.1
255 189
165

As you can see, it completely skips the width and height values and uses the next 2 values in place of it for some reason... 如您所见,由于某种原因,它完全跳过了width和height值并使用接下来的2个值代替它。

Here is my code: 这是我的代码:

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

#define COMMENT_LENGTH 256
#define COMMENT_ARRAY_SIZE 10
#define MAX_PIXEL_HEIGHT 480
#define MAX_PIXEL_WIDTH 640

typedef struct PPM {
    char format[2]; //2 letter code for PPM format
    char comments[COMMENT_LENGTH][COMMENT_ARRAY_SIZE]; //comment array
    int width; //number of columns
    int height; //number of rows
    int max; //maximum colour value (usually 255)
    int rgbPixels[MAX_PIXEL_WIDTH * MAX_PIXEL_HEIGHT][3]; //integers between 0 and max for pixel i's RGB values
}PPM;

struct PPM * getPPM(FILE *fd);

int main(int argc, char **argv) {
    FILE *file = fopen("ape.ppm", "r");
    if(file == NULL) return 0;
    else {
        struct PPM *newPPM = getPPM(file);

        return 0;
    }
}

struct PPM * getPPM(FILE *fd) {
    if(fd == NULL) {
        return NULL;
    }

    struct PPM *newPPMFile = (PPM *) malloc(sizeof(PPM));

    fscanf(fd, "%2s\n", newPPMFile->format);
    printf("%2s\n", newPPMFile->format);

    //check for comments
    int i = 0;
    char str[COMMENT_LENGTH];
    while(i < COMMENT_ARRAY_SIZE && fgets(str, COMMENT_LENGTH, fd) != NULL) {
        if(str[0] != '#') {
            break;
        } else {
            strcpy(newPPMFile->comments[i], str);
            printf("%s", newPPMFile->comments[i]);
        }
    }

    //read width and height
    fscanf(fd, "%d %d", &newPPMFile->width, &newPPMFile->height);
    printf("%d %d\n", newPPMFile->width, newPPMFile->height);

    //read max
    fscanf(fd, "%d", &newPPMFile->max);
    printf("%d\n", newPPMFile->max);

    //read rgb data in rgb array (INCOMPLETE)


    //close file
    fclose(fd);

    return newPPMFile;
};

There are a couple things here: 这里有几件事:

while(i < COMMENT_ARRAY_SIZE && fgets(str, COMMENT_LENGTH, fd) != NULL) {
    if(str[0] != '#') {
        break;

The position for the next read (offset) has already advanced, if you break or not. 如果不中断,则下一个读取(偏移)的位置已经提前。 So naturally, it'll continue at the advanced offset, like you experienced here. 因此,自然会像您在此处体验的那样,以高级偏移量继续。

Also, 也,

(PPM *) malloc(sizeof(PPM));

Casting the result of malloc() is unnecessary and potentially masks errors. 强制转换malloc()的结果是不必要的,并且可能掩盖错误。

fgets reads the full line into the buffer. fgets将整行读入缓冲区。 It it doesn't begin with a hash mark, you lose the data on that line. 它不是以井号开头的,您会丢失该行上的数据。

A solution is to use fscanf throughout. 一个解决方案是始终使用fscanf fscanf stops scanning when the pattern isn't matched or if a conversion can't be made. 当模式不匹配或无法进行转换时, fscanf停止扫描。 So if you enforce a hash mark before the comment, but the line doesn't begin with a hash mark, the rest of the line is untouched: 因此,如果您在注释之前强制使用井号,但该行不是以井号开头,则其余部分保持不变:

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

int main(void)
{
    int width, height, max;
    char buf[80];                             // temporary buffer
    FILE *fd = fopen("kk", "r");

    if(fd == NULL) return 1;                  // TODO: Error message

    fscanf(fd, "%79s", buf);
    if (strcmp(buf, "P3") != 0) return 1;     // TODO: Error message

    while (fscanf(fd, " # %79[^\n]%*[^\n]", buf) == 1) {
        printf("Comment: %s\n", buf);
    }

    fscanf(fd, "%d %d", &width, &height);     // TODO: Check success
    printf("%d x %d\n", width, height);

    fscanf(fd, "%d", &max);                   // TODO: Check success
    printf("max: %d\n", max);

    fclose(fd);    
    return 0;
}

There are some things to keep in mind, though: 不过,请记住以下几点:

  • fscanf does not care or know about new lines; fscanf不在乎或不知道fscanf行; new-line characters are just white space. 换行符只是空白。 That means that your first hash mark could be on the same line with the file format P3 . 这意味着您的第一个哈希标记可能与文件格式P3在同一行。
  • What is an advantage in reading the comments may be a pitfall when you read the values: The code above doesn't check whether a conversion was made. 读取值时,读取注释的一个优点可能是一个陷阱:上面的代码不检查是否进行了转换。 That's not good, especially that if you read EOF or a string that isn't an integer, fscanf gets stuck. 这不好,特别是如果您读取EOF或不是整数的字符串,则fscanf会卡住。
  • The format %79[^\\n] will read only up to 79 characters. 格式%79[^\\n]最多只能读取79个字符。 If the comment line is longer, the file position will not be on the new-line character, this srewing up the reading of subsequent lines. 如果注释行较长,则文件位置将不在换行符上,这将增加后续行的读取。 To circumvent that, you can add %*[^\\n] after that: This will enforce that you read to the next new-line character, but it won't store the results. 为了避免这种情况,您可以在此之后添加%*[^\\n] :这将强制您读取到下一个换行符,但不会存储结果。 ( * means "don't store result" in scanf formats.) That way you get up to the first 80 characters of each comment line and also ensure that the line is read completely if it is longer. *表示scanf格式的“不存储结果”。)这样,您最多可以获取每条注释行的前80个字符,并且还可以确保较长的行可以完全读取。
  1. Insufficient space @errikos . 空间不足@errikos

     // char format[2]; //2 letter code for PPM format char format[2 + 1]; //2 letter code for PPM format ... // 2 is the max width of non-white-space characters to scan fscanf(fd, "%2s\\n", newPPMFile->format); 
  2. Check the return values form fscanf() 检查fscanf()的返回值

     // fscanf(fd, "%d %d", &newPPMFile->width, &newPPMFile->height); if (fscanf(fd, "%d %d", &newPPMFile->width, &newPPMFile->height) != 2) { fprintf(stderr, "Error reading width & height\\n"); } 
  3. Code mixes fscanf() with fgets() . 代码将fscanf()fgets() Tis often is a problem as many formats used to not consume that trailing '\\n`` and then a following fgets() simply reads just that one character. Reccomedn only using Tis通常是一个问题,因为许多格式以前都不使用该结尾的'\\n`` and then a following fgets() simply reads just that one character. Reccomedn only using simply reads just that one character. Reccomedn only using fgets()`. simply reads just that one character. Reccomedn only using fgets()推荐。

  4. Possibly other important issues too. 可能还有其他重要问题。

here is the root of the problem. 这是问题的根源。

in the loop reading comments: 在循环中阅读评论:

when the line is read (when reading comments) that does not start with a #, then the code has already read width+height values from the input file. 当读取不是以#开头的行时(读取注释时),则该代码已从输入文件中读取width + height值。

So the code needs to parse those values from the already read line. 因此,代码需要从already read行中解析这些值。

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

相关问题 程序卡住了,管道文件描述符何时不应该打开? - Program stuck, pipe file descriptor open when shouldn't? gdb“程序正常退出” - gdb “Program exited normally” when it shouldn't C程序fscanf跳过行 - C Program fscanf skips lines 当程序从文件中读取字符时,它也会读取一些垃圾 - when program reads characters from file it also reads some trash 该程序从用户读取“ n”行并将其写入C中的文本文件 - Program that reads “n” lines from the user and writes it to a text file in C 从文件中读取多行并转换为单行字符串的程序 - Program that reads multiple lines from a file and converts to a single line string 我的 C 程序不应该打印两种不同的东西 - My C program prints two different things when it shouldn't C-程序读取文本文件时未注意到对文本文件所做的更改 - C - Changes made to text file are not noticed when the program reads the file 该程序读取一个文本文件作为输入并生成一个输出文件,该文件的所有原始行均按字母顺序排列 - Program that reads in a text file as input and produces an output file which has all the original lines in alphabetical order 读取文本文件并显示除所有空白行和注释之外的每一行的C程序 - C program that reads in a text file and displays each line except for all blank lines and comments
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM