【问题标题】:Sorting file using system and library functions使用系统和库函数对文件进行排序
【发布时间】:2017-03-22 18:35:16
【问题描述】:

@编辑 看起来 fread 函数读取的字符比 record_size 参数多;x

PICTURE

我有 2 个函数,它们按记录排序文件(冒泡排序)(键是第一个字符)。第一个是使用系统函数(读、写等),第二个是使用库函数(fread、fwrite 等)。对于小的 record_size 参数都可以正常工作,但例如对于 record_size = 5000 只有 sys_sort 可以正常工作。由 lib_sort 排序的文件行数更少,长度不同。为什么?不知道是什么问题。

void lib_sort(const char *filename, long long int record_size, long long int num_of_lines) {
    record_size++;  // '\n' char at the end of line
    FILE *file;

    if (!(file = fopen(filename, "r+"))) {
        printf("Cannot open %s file.\n", filename);
        fclose(file);
        exit(EXIT_FAILURE);
    }

    char *buffer1 = malloc(sizeof(char) * record_size);
    char *buffer2 = malloc(sizeof(char) * record_size);

    bool flag = true;

    while (flag) {
        flag = false;
        if(fseek(file, 0, SEEK_SET) != 0) {
            printf("fseek failed.\n");
        }
        if((fread(buffer1, sizeof(char), (size_t) record_size, file)) != record_size) {
            printf("fread failed.\n");
        }

        for (int i = 1; i < num_of_lines; ++i) {
            if((fread(buffer2, sizeof(char), (size_t) record_size, file)) != record_size) {
                printf("fread failed.\n");
            }
            if (buffer1[0] > buffer2[0]) {
                if(fseek(file, record_size * (-2), SEEK_CUR) != 0) {
                    printf("fseek failed.\n");
                }
                if((fwrite(buffer2, sizeof(char), (size_t) record_size, file)) != record_size) {
                    printf("fwrite failed.\n");
                }

                if((fwrite(buffer1, sizeof(char), (size_t) record_size, file)) != record_size) {
                    printf("write failed.\n");
                }
                flag = true;
            } else {
                char *tmp = buffer2;
                buffer2 = buffer1;
                buffer1 = tmp;
            }
        }
        num_of_lines--;
    }
    fclose(file);
    free(buffer1);
    free(buffer2);
}

这是正确的:

void sys_sort(const char *filename, long long int record_size, long long int num_of_records) {
    record_size++;  // '\n' char at the end of line
    int file;

    if ((file = open(filename, O_RDWR)) < 0) {
        printf("Cannot open %s file.\n", filename);
        close(file);
        exit(EXIT_FAILURE);
    }

    char *buffer1 = malloc(sizeof(char) * record_size);
    char *buffer2 = malloc(sizeof(char) * record_size);

    bool flag = true;

    while (flag) {
        flag = false;
        lseek(file, 0, SEEK_SET);
        read(file, buffer1, (size_t) record_size);

        for (int i = 1; i < num_of_records; ++i) {
            read(file, buffer2, (size_t) record_size);
            if (buffer1[0] > buffer2[0]) {
                lseek(file, record_size * (-2), SEEK_CUR);
                write(file, buffer2, (size_t) record_size);
                write(file, buffer1, (size_t) record_size);
                flag = true;
            } else {
                char *tmp = buffer2;
                buffer2 = buffer1;
                buffer1 = tmp;
            }
        }
        num_of_records--;
    }
    close(file);
    free(buffer1);
    free(buffer2);
}

我使用 ubuntu 16.04 和标准 C99

【问题讨论】:

  • 我建议的第一件事是检查这些系统调用中是否有任何失败以及原因。像if( fread(...) != record_size ) { perror("fread failed to read sufficient data") } 这样的东西。 fseekfwrite 相同。
  • 抱歉,我无法重现您的问题。我制作了一个包含 5 行的文件,每行以一个数字开头,然后是 4999 x。两者都运行良好。
  • 我刚刚做了测试,没有打印错误。对于 record_size = 5000 和 num_or_record = 10 的 lib_sort 仍然不起作用。
  • 请用这些测试编辑你的代码。您能否详细说明什么“不起作用”?还要说明你是如何调用这些函数的。
  • 结果文件只有更少的行和不同的行长度(多于和少于 5000)。我发现了一个错误,它读取的字符比我的 record_size 参数多,我在 buffer1 的末尾有这样的东西:jfuhaypwjgsgjxl\021\020

标签: c sorting


【解决方案1】:

您错误地使用了fread()fwrite()

size_t fread(void *ptr, size_t size, size_t nmemb, FILE * stream );

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

说明

函数fread()stream 指向的流中读取nmemb 数据元素,每个size 字节长,并将它们存储在ptr 指定的位置。

函数fwrite()nmemb数据元素写入stream指向的流中,每个size字节长,从ptr给出的位置获取它们。

您告诉fread()fwrite(),您的记录或项目的长度是 1 字节长,并且您要求 5000 条记录。

返回值

成功时,fread()fwrite() 返回读取或写入的项目数。此数字等于仅当 size 为 1 时传输的字节数。如果发生错误,或到达文件末尾,则返回值是一个短项计数(或零)。

您传递给 fread()fwrites() 的参数顺序错误,而在您的代码中您明确表示记录大小(项目的长度)为 record_size 或在失败情况下为 5000。

您应该编写代码以这种方式调用fread()

fread(buffer1, (size_t) record_size, 1, file)

并以这种方式调用fwrite()

fwrite(buffer2, (size_t) record_size, 1, file)

还应注意fread()fwrite() 适用于二进制流。这意味着字符串不会自动以 null 终止,并且读取将读取过去的换行符和过去的 null \0 字节。在写入时,换行符不会自动转换为操作系统支持的换行符,例如 Linux 上的 LF 和 Windows 上的 CRLF

对于字符串操作,请改用fgets()fputs()

您忘记提及了,我错误地认为您在 Linux 上运行。根据您的评论,您毕竟是在 Windows 上运行的。在 Windows 上,当文件以text 模式打开时,fread()fwrite() 将无法正常工作,因为转换与操作系统相关的编码。您需要以binary 模式打开文件。

【讨论】:

  • 其实在你回答link之前我已经尝试过了,但它仍然无法正常工作。我认为问题出在 fread 和 fwrite 函数中。我创建了一个文件,然后调用了 fread 和 fwrite 函数。我将加载的字符串与文件中的行进行了比较,结果是一样的。然后在 fwrite 函数之后(将第一条记录写入第二条)它们是不同的!(通常大约 4000 个第一个字符相同,其余的不同)。 fwrite 失败并且总是返回 record_size(或 1 在你的调用选项中)。
  • 您对返回值的解释不正确。 fwrite() 将返回您的代码中写入的字节数,并在我的建议中返回 1。这两个都意味着写入成功。但你错误地假设那些失败了。
  • 啊,你毕竟在运行 Windowze。那么这是你的问题stackoverflow.com/questions/3187693/…
  • @bednius - 在 Windows 上,当使用 fread()fwrite() 时,您需要在 binary 中打开文件。
  • 我理解你,正如我所说,我之前尝试过这个版本,但它不起作用。程序没有写入任何错误(这意味着 fread 和 fwrite 成功,但实际上并没有,因为文件内容与预期不同)
【解决方案2】:

我在每个 fread()fwrite() 函数后面加上 fseek(file, 0, SEEK_CUR);,这对我有用。我不知道为什么。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-26
  • 2019-03-15
相关资源
最近更新 更多