使用系统和库函数对文件进行排序

时间:2017-03-22 18:35:16

标签: c sorting

@EDIT 看起来像fread函数读取比record_size参数更多的字符; x

PICTURE

我有2个按记录排序文件(冒泡排序)的功能(键是第一个字符)。第一个是使用系统函数(读,写等),而secong正在使用库函数(fread,fwrite等)。对于small 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

2 个答案:

答案 0 :(得分:0)

您错误地使用了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()nmemb指向的流中读取size个数据元素,每个stream个字节长,将它们存储在{ptr给出的位置1}}。

     

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

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

  

返回值

     

成功时,fread()fwrite() 会返回读取或写入的项目数 。此数字等于仅在大小为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()适用于二进制流。这意味着字符串不会自动为空终止,并且读取将读取过去的换行符并超过空\0个字节。写入时,换行符不会自动转换为操作系统支持的换行符,例如Linux上的LF和Windows上的CRLF

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

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

答案 1 :(得分:0)

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