在 C 中读取文件时,我可以忽略以“#”开头的行吗?

Can I ignore a line started with "#" while reading a file in C?

提问人:Duartinho Codes 提问时间:11/4/2023 最后编辑:genpfaultDuartinho Codes 更新时间:11/5/2023 访问量:101

问:

以下代码用于读取文件.pbm

int **leArquivoImagem(char *nomeImagem, char *tipo, int *lin, int *col)
{
    FILE *arq = fopen(nomeImagem, "r");
    if (arq == NULL)
    {
        printf("\nErro ao abrir arquivo - leArquivoImagem.\n");
        return NULL;
    }
    fscanf(arq, "%s", tipo);
    printf("%s\n", tipo);

    //line ignorer here

    fscanf(arq, "%d %d", col, lin);
    printf("%d %d\n", *lin, *col);
    int **mat = alocaMatrizImagem(*lin, *col);
    if (mat == NULL)
    {
        printf("\nErro ao alocar mat imagem - leArquivoImagem.\n");
        return NULL;
    }
    for (int i = 0; i < *lin; i++)
    {
        for (int j = 0; j < *col; j++)
        {
            fscanf(arq, "%d", &mat[i][j]);
        }
    }
    fclose(arq);
    return mat;
}

这就是我正在阅读的文件:

P1
5 3
0 0 1 0 1
0 0 1 1 0
1 1 0 0 0

但在某些情况下,文件可以有注释行,如下所示:

P1
# comment here
5 3
0 0 1 0 1
0 0 1 1 0
1 1 0 0 0

甚至像这样:

P1
# comment here
# another comment to ignore
5 3
0 0 1 0 1
0 0 1 1 0
1 1 0 0 0

我怎样才能插入这些线条?(注释始终介于“P1”和尺寸之间)。

我尝试在以下代码中使用最大行大小 (2047) 的缓冲区:

char line[2047];
while (fgets(line, sizeof(line), arq) != NULL)
    {
        char *hash = strchr(line, '#');
        if (hash != NULL)
            *hash = '\0';
    }

    char buffer[2047];
    while (fgets(buffer, 2047, arq) != NULL) {
        if (buffer[0] != '#') {
            break;
        }
    }

    char line[2047];
    while (fgets(line, sizeof(line), arq)) {
        if (line[0] == '#') {
            continue;
        }
    }
C 文件 PBM

评论

5赞 John Kugelman 11/4/2023
事实上,你可以:你自己已经展示了三种方法。它们不起作用吗?你对他们有问题吗?
1赞 YuWea 11/4/2023
读取行时,代码中不相关但相关的建议:如果最大行大小是文本的最大长度,则缓冲区大小应为(文本为 2047,字符为 1)2048\0
1赞 Duartinho Codes 11/4/2023
约翰·库格尔曼(JohnKugelman)没有一个奏效,这就是问题所在。@YuWea感谢您的建议!
1赞 Jonathan Leffler 11/4/2023
该版本很可能是正确的。版本不正确;您不想因为注释行而停止阅读文件。如果您的行处理代码干净地处理空行,则另一个版本可能没问题。当然,会有字符串处理代码,可能在循环中使用 sscanf() 来处理该行。continuebreak
1赞 Duartinho Codes 11/5/2023
@chux-ReinstateMonica 感谢您的建议,我将更改我的代码以仅使用 fgets。

答:

0赞 SmellyCat 11/4/2023 #1

完成这些调用后,您需要检查缓冲区,以防它不是注释行。你这样做,而不是在不支持注释时使用。fgetsscanffscanf

char line[2047];
while (fgets(line, sizeof(line), arq) != NULL)
{
    char *hash = strchr(line, '#'); /* You might be able to combine this line into the if-statement. */
    if (hash != NULL)
        continue; /* comment line */
    
    sscanf(line, "%d %d", col, lin);
    printf("%d %d\n", *lin, *col);
    int **mat = ....

评论

0赞 chux - Reinstate Monica 11/4/2023
这将跳过包含 的行,即使不是第一个字符。OP 的目标是<忽略以“#”开头的行>'#'
0赞 stark 11/4/2023
您没有检查 sscanf 的返回值。
1赞 Duartinho Codes 11/5/2023 #2

以下代码解决了我的问题。感谢 Chux 建议仅使用 、YuWea 进行缓冲区大小校正,以及 Jonathan Leffler 建议 和 。fgets()sscanf()break

int **leArquivoImagem(char *nomeImagem, char *tipo, int *lin, int *col) {
    FILE *arq = fopen(nomeImagem, "r");
    if (arq == NULL) {
        printf("\nErro ao abrir arquivo - leArquivoImagem.\n");
        return NULL;
    }

    char buffer[2048];
    while (fgets(buffer, sizeof(buffer), arq) != NULL) {

        sscanf(buffer, "%s", tipo);
        printf("%s\n", tipo);

        // Ignore all commented lines and get dimensions
        while (fgets(buffer, sizeof(buffer), arq) != NULL) {
            if (buffer[0] != '#') {
                sscanf(buffer, "%d %d", col, lin);
                printf("%d %d\n", *lin, *col);
                break;
            }
        }

        int **mat = alocaMatrizImagem(*lin, *col);
        if (mat == NULL) {
            printf("\nErro ao alocar mat imagem - leArquivoImagem.\n");
            fclose(arq);
            return NULL;
        }

        int count = 0;
        for (int i = 0; i < *lin; i++) {
            fgets(buffer, sizeof(buffer), arq);
            char *ptr = buffer;
            for (int j = 0; j < *col; j++) {
                while (*ptr == ' ') ptr++;
                if (*ptr == '\n' || *ptr == '\0') {
                    j--;
                    continue;
                }
                mat[i][j] = strtol(ptr, &ptr, 10);
            }
        }

        fclose(arq);
        return mat;
    }

    fclose(arq);
    return NULL;
}