比较两个不同文件中的每一行并打印 C 中不同的行

标签 c io

假设我有两个这样的文件:

file1.txt

john
is
the new
guy

file2.txt

man
the old
is
rick
cat
dog

我想将 file1 的第一行与 file2 的所有行进行比较,并验证它是否存在。如果不是,则从 file1 的第二行开始,并将它与 file2 的所有行进行比较......以此类推,直到到达 eof file1.

我期望的输出是:

john
the new
guy

我认为应该怎么做:

  • 读取file1file2
  • 创建一个函数返回每个行号
  • file1 中取出第一行并将其与 file2 中的所有行进行比较>
  • 这样做直到 file1 中的所有行都被浪费

现在,我不知道我做错了什么,但我没有得到我期望的结果:

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

int countlines(char *filename)
{                                
    int ch = 0, lines = 0;
    FILE *fp = fopen(filename, "r");
    if (fp == NULL)
        return 0;

    do {
        ch = fgetc(fp);
        if (ch == '\n')
            lines++;
    } while (ch != EOF);

    if (ch != '\n' && lines != 0)
        lines++;
    fclose(fp);

    return lines;
}

int main(int argc, char *argv[])
{
    FILE *template_file = fopen(argv[1], "r");
    FILE *data_file = fopen(argv[2], "r");

    char buffer_line_template_file[100];
    char buffer_line_data_file[100];


    if (argc != 3)
    {
        perror("You didn't insert all the arguments!\n\n");
        exit(EXIT_FAILURE);
    }

    if (template_file == NULL || data_file == NULL)
    {
        perror("Error while opening the file!\n\n");
        exit(EXIT_FAILURE);
    }

    int counter = 0;
    for (int i = 0; i < countlines(argv[1]); i++)
    {
        fgets(buffer_line_template_file, 100, template_file);

        for (int j = 0; j < countlines(argv[2]); j++)
        {
            fgets(buffer_line_data_file, 100, data_file);

            if (strcmp(buffer_line_template_file, buffer_line_data_file) != 0)
            {
                counter++;
                printf("%d", counter);
            }
        }
    }

    printf("\n\n");

    return 0;
}

有人可以指出我正确的方向吗?出于测试目的,我在最后创建了一个计数器,这是一个小调试的一部分。应该有 print() 函数


根据 @chux answer我得到以下简化代码:

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

int main(int argc, char *argv[])
{
    FILE *template_file = fopen(argv[1], "r");
    FILE *data_file = fopen(argv[2], "r");

    char buffer_line_template_file[100];
    char buffer_line_data_file[100];


    if (argc != 3)
    {
        perror("You didn't insert all the arguments!\n\n");
        exit(EXIT_FAILURE);
    }

    if (template_file == NULL || data_file == NULL)
    {
        perror("Error while opening the file!\n\n");
        exit(EXIT_FAILURE);
    }

    while(fgets(buffer_line_template_file, 100, template_file))
    {
        buffer_line_template_file[strcspn(buffer_line_template_file, "\n")] = '\0';

        rewind(data_file);
        while (fgets(buffer_line_data_file, 100, data_file))
        {
            buffer_line_data_file[strcspn(buffer_line_data_file, "\n")] = '\0';

            if (strcmp(buffer_line_template_file, buffer_line_data_file) != 0)
            {
                printf("%s\n", buffer_line_template_file);
            }
        }
    }

    printf("\n\n");

    return 0;
}

上面的代码给出了以下输出,这不是预期的:

john
john
john
john
john
john
is
is
is
is
is
the new
the new
the new
the new
the new
the new
guy
guy
guy
guy
guy
guy

最佳答案

OP 的代码有问题

  1. 线的定义不精确。

  2. 过度重新计算

  3. 文件行数的模糊判断。


  1. 不像 string,它在 C 中有精确的定义,读取 line 的定义不是那么明确。主要的特异性问题:一行是否包含结尾的 '\n'。如果第一个答案是,那么文件中'\n' 之后的最后一个文本是否构成一行? (排队过长是另一个问题,但我们今天不处理它。)

因此可能 一些 行以 '\n' 结尾,而其他行则没有,这欺骗了 strcmp("dog", "dog\n").

最简单的解决方案是读取 ,直到 1) 遇到 '\n',2) EOF 发生或 3 ) 行缓冲区已满。然后在得到一行后,去掉尾随 '\n'potential

现在所有代码随后都没有'\n'

fgets(buffer_line_template_file, 100, template_file);
buffer_line_template_file[strcspn(buffer_line_template_file, "\n")] = '\0';
  1. OP 的循环非常浪费。考虑一个包含 1000 行的文件。代码将循环,调用 1000 次 countlines()(每个 countlines() 调用读取 1000 行)次,而一次 countlines() 调用就足够了.

    // for (int j = 0; j < countlines(argv[2]); j++)
    int j_limit = countlines(argv[2]);
    for (int j = 0; j < j_limit; j++)
    
  2. 确实没有必要计算行数,继续直到 EOF(fgets() 返回 NULL)。因此无需修复其模糊定义。 (模糊性涉及与#1 相同的问题)

    int counter = 0;
    for (fgets(buffer_line_template_file, 100, template_file)) {
      buffer_line_template_file[strcspn(buffer_line_template_file, "\n")] = '\0';
    
      rewind(data_file);
      while ((fgets(buffer_line_data_file, 100, data_file)) {
        buffer_line_data_file[strcspn(buffer_line_data_file, "\n")] = '\0';
    
        if (strcmp(buffer_line_template_file, buffer_line_data_file) != 0) {
          counter++;
          printf("%d", counter);
        }
      }
    }
    

其他可能的简化 - 改天再说。


FWIW,以下计数 文本允许文件中的最后一行可选择以 '\n' 结尾。

    unsigned long long FileLineCount(FILE *istream) {
      unsigned long long LineCount = 0;
      rewind(istream);
      int previous = '\n';
      int ch;

      while ((ch = fgetc(inf)) != EOF) { 
        if (previous == '\n') LineCount++;
        previous = ch;
      }
      return LineCount;
    }

请注意,此函数可能会得到与 fgets() 调用不同的结果。考虑一个包含 150 个字符的文件。 fgets(..., 100,...) 将报告 2 行。 FileLineCount() 报告 1。

[编辑] 更新代码以符合 OP 功能。

    int found = 0;
    while (fgets(buffer_line_data_file, 100, data_file))
    {
        buffer_line_data_file[strcspn(buffer_line_data_file, "\n")] = '\0';

        if (strcmp(buffer_line_template_file, buffer_line_data_file) == 0)
        {
            found = 1;
            break;
        }
    }
    if (!found) printf("%s\n", buffer_line_template_file);

关于比较两个不同文件中的每一行并打印 C 中不同的行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37667382/

相关文章:

c - 这个C代码有问题

c - 如果在头文件中声明函数,C 中的单独编译会出错

计算函数内部数组中的元素

Java 文件 I/O 帮助

c++ - fstream::read 的结果不一致

c - 从文本文件读取数据到数组并使用c中的共享内存发送它

c++ - 即使已设置包含路径,Eclipse 也找不到头文件管理器

logging - Log4Net RollingFileAppender 不会用低容量日志刷新 IO 缓冲区

python - 通过Python写入/etc/hosts时IOError : 13, 'Permission denied'

java - 来自音频文件的 Android 基本 TTS 引擎