【问题标题】:fgets() does not read the whole filefgets() 不读取整个文件
【发布时间】:2015-07-19 21:18:42
【问题描述】:

我正在编写一个程序,它基本上在一个目录及其所有子目录中搜索重复文件。我已经根据您的建议完善了问题和代码(需要返回默认值的函数已被修复)所以这里......

下面是比较函数的代码:

int compare()
{
    int a, b;
    unsigned char byte1, byte2;

    while(1)
    {
        a = fread(&byte1, 1, 1, file1);
        b = fread(&byte2, 1, 1, file2);
        if(a == 0 && b == 0) break;
        if(a != b) return 1;
        if(byte2 != byte1) return 1;
    }

    return 0;
}

void startCompare()
{
    char path1[1000], path2[1000];
    FILE *reference = fopen("list.comp", "r");
    FILE *other = fopen("list2.comp", "r");
    int i, flag, j;
    i = 0;

    while(fgets(path1, 1000, reference))
    {
        flag = 0;
        strtok(path1, "\n");  
        openFile1(path1);
        for(j = 0; j <= i; ++j)
        {
            fgets(path2, 1000, other);
        }
        while(fgets(path2, 1000, other))
        {
            strtok(path2, "\n");
            openFile2(path2);
            if(!compare())
            {
                printf("Checking: %s vs. %s --> DUPLICATE\n", path1, path2);
                flag = 1;
                break;
            }
            else
            {
                printf("Checking: %s vs. %s --> DIFFERENT\n", path1, path2);
            }
        }
        if(flag == 1)
        {
            printf("Will be deleted.\n");
        }
    }
}

(先调用startCompare()函数)

现在,目录本身有这些文件:

  • bloblo
  • bloblo/frofo
  • bloblo/frofo/新建文件夹
  • bloblo/frofo/新建文件夹 (2)
  • bloblo/frofo/新建文件夹 (2)/新建文件夹 (3)
  • bloblo/frofo/新建文件夹 (2)/新建文件夹 (3)/新建文本 Document.txt
  • bloblo/frofo/新建文件夹 (2)/新建文件夹 (3)/Untitled4
  • 0.comp
  • 1.comp
  • 2.comp
  • 3.comp
  • 4.comp
  • 5.comp
  • 11.comp
  • 100.comp
  • duplicate_delete.dev
  • duplicate_delete.exe
  • duplicate_delete.layout
  • list.comp
  • list2.comp
  • main.c
  • main.o
  • Makefile.win
  • Untitled5.c
  • Untitled5.exe

输出是:

Checking: 0.comp vs. 1.comp --> DIFFERENT
Checking: 0.comp vs. 100.comp --> DIFFERENT
Checking: 0.comp vs. 11.comp --> DIFFERENT
Checking: 0.comp vs. 2.comp --> DIFFERENT
Checking: 0.comp vs. 3.comp --> DIFFERENT
Checking: 0.comp vs. 4.comp --> DIFFERENT
Checking: 0.comp vs. 5.comp --> DIFFERENT
Checking: 0.comp vs. duplicate_delete.dev --> DIFFERENT
Checking: 0.comp vs. duplicate_delete.exe --> DIFFERENT
Checking: 0.comp vs. duplicate_delete.layout --> DIFFERENT
Checking: 0.comp vs. list.comp --> DIFFERENT
Checking: 0.comp vs. list2.comp --> DIFFERENT
Checking: 0.comp vs. main.c --> DIFFERENT
Checking: 0.comp vs. main.o --> DIFFERENT
Checking: 0.comp vs. Makefile.win --> DIFFERENT
Checking: 0.comp vs. Untitled5.c --> DIFFERENT
Checking: 0.comp vs. Untitled5.exe --> DIFFERENT

返回码为 0。

虽然它应该打印的是每个文件都被相互检查并发现文件 100.comp 和 11.comp 是彼此的副本并且其他文件是唯一的。所以基本上,为什么它停在那里?为什么不继续检查?有什么办法可以解决吗?

【问题讨论】:

  • 请说明你有哪些文件(你的列表格式搞砸了),预期的输出是什么,你得到什么输出。请尝试删除不需要证明问题的文件(阅读this 可能也有帮助)。另外,请询问有关一个代码版本的问题 - 有或没有fclose - 这将减少混乱。
  • compare 使用 feof 错误,最后缺少返回语句。
  • 首先确保所有返回值的函数都返回值。 main 被声明为返回 int,但不返回任何内容。 openFile1 在您无法打开文件时返回 0,但在可以时从堆栈中返回垃圾。 openFile2 也是如此。当所有 ifs 语句都不为真时,会返回什么 compare?垃圾……
  • 请注意sizeof(unsigned char)的定义是1
  • 您最近的编辑混淆了整个帖子。推荐 1) 将帖子恢复到“根据您的建议优化问题和代码”之前 2) 接受 @Weather Vane 3) 发布一个涉及此问题的 问题 4) 确保您的新问题帖子是完全可编译的,以最少的输入行显示剩余的问题。

标签: c windows winapi stdio


【解决方案1】:

我不知道这是否会回答您的 TLDR 问题和代码,但这对于评论来说太过分了。

您的函数compare() 永远不会返回0,如果您启用并注意到编译器警告,您就会知道这一点。该函数还使用了可怕的feof()。见why feof() is wrong

我建议更换这个

int compare()
{
    while(!feof(file1))
    {
        fread(&byte1, sizeof(unsigned char), 1, file1);
        fread(&byte2, sizeof(unsigned char), 1, file2);
        if(byte2 != byte1) return 1;
    }
    if(feof(file1) && (!feof(file2))) return 1;
    if(feof(file2) && (!feof(file1))) return 1;
}

这样,因为检查fread()读取的数据量是测试文件结尾的方法。

int compare()
// return 0 if files are the same
// *** always include a comment to tell you what the function does / returns ***
{
    size_t read1, read2;
    while(1) {
        read1 = fread(&byte1, 1, 1, file1);
        read2 = fread(&byte2, 1, 1, file2);
        if (read1==0 && read2==0)
            break;             // success: both files ended
        if (read1 != read2)
            return 1;          // bad: one of them read, other didn't
        if (byte2 != byte1)
            return 1;          // bad: files read different data
    }
    return 0;
}

请注意sizeof(unsigned char) 是完全没有必要的,它是 1。

我也会将byte1byte2 作为局部变量。

【讨论】:

    【解决方案2】:

    回答您实际提出的问题(为什么不比较所有文件对):

    您的程序首先从list.comp 读取第一行。然后,它从list2.comp 读取每一行并比较文件。

    然后,它从list.comp 中读取下一行,并再次尝试将其与list2.comp 中的所有文件进行比较。但它已经在list2.comp 的末尾,所以它不再从list2.comp 读取任何文件名。

    您可以使用rewind(other);“倒回”到list2.comp 的开头,以便再次读取文件名。

    【讨论】:

      【解决方案3】:

      抱歉,如果您正在搜索重复文件,那么您使用的方法效率低下。最好在它们上运行 md5sum(1) 并对生成的列表进行排序。然后,您将比较一行和下一行以获得相等的 md5 值。如果您不信任 md5sum(1)(有人说不同的文件可以给出相同的校验和),您可以只比较文件内容(但只能在已经匹配的 md5 校验和上)。到目前为止,这比您的方法有效得多。可以通过以下方式解决:

      find <dir> -type f -name "glob_pattern" -print0 | xargs -0 md5sum | sort >files.md5sum
      

      然后,编辑文件files.md5sum 并搜索/^\([0-9a-f]*\) .*\n\1/ 模式以获得重复的md5。您甚至可以多次重复同一个文件。

      注意

      请注意空文件的 MD5 校验和相同,并且所有文件比较相等。您也会在您的列表中看到它。

      【讨论】:

        猜你喜欢
        • 2020-06-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-21
        • 1970-01-01
        相关资源
        最近更新 更多