fgets() 不读取整个文件

fgets() does not read the whole file

我正在编写一个程序,主要用于搜索目录及其所有子目录以查找重复文件。我根据您的建议改进了问题和代码(需要 return 默认值的函数已被修复)所以这里是...

这里是比较函数的代码:

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()函数)

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

输出为:

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

使用 return 代码 0。

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

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

你的函数 compare() 永远不会 returns 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 作为局部变量。

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

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

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

读取任何文件名

您可以使用 rewind(other); 来 "rewind" 回到 list2.comp 的开头,这样您就可以再次读取文件名。

抱歉,如果您要搜索重复文件,则说明您使用的方法效率低下。最好对它们进行 运行 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/ 模式以获取重复的 md5。您甚至会得到同一文件的多次重复。

备注

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