无法通过fwrite复制文本文件并在C中进行fread

时间:2017-06-24 20:54:10

标签: c file file-io fwrite fread

以下是代码:

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

int main() {
    FILE *f, *fp;
    char buff[512];
    int buff_size;
    int bytes;

    fp = fopen("File.txt", "rb");

    if (fp == NULL) {
        printf("Cannot Open Source File!\n");
        exit(1);
    }

    f = fopen("append.txt", "ab+");

    if (f == NULL) {
        printf("Cannot Open Target File!\n");
        fclose(fp);
        exit(1);
    }

    buff_size = sizeof(buff);

    while (bytes = fread(&buff, buff_size, 1, fp) > 0) {
        if (bytes > 0)
            fwrite(&buff, buff_size, 1, f);
        else
            break;

        printf("Appending...\n\n");
    }

    rewind(f);

    while (bytes = fread(&buff, buff_size, 1, f) > 0)
        if (bytes > 0)
            printf("%s", buff);


    fclose(fp);
    fclose(f);
}

所以,它恰好是没有输出任何东西,当我检查文件“append.txt”时它也不包含任何内容。 请注意,源文件“File.txt”不为空。 谁能告诉我它有什么问题?

修改

我通过将buff_size替换为strlen(buff)来修复此问题: bytes = fread(&buff, strlen(buff), 1, f) > 0fwrite()以及fread()中的select FINALSCORE from tennismatch join tennismatch_tennisset on tennismatch.ID = tennismatch_tennisset.TennisMatch_ID and tennismatch.ID = 1 join tennisset on tennismatch_tennisset.mapOfSets_ID = tennisset.ID 相同。

有人可以解释为什么会这样吗?

4 个答案:

答案 0 :(得分:2)

char buff[512];
int buff_size;

// [...]

bytes = fread(&buff, buff_size, 1, fp)

这将尝试读取一个512字节的块。返回值是读取的块数,因此它不是字节。但抛开这一点,如果你的文件短于512字节,这将不会读取任何

你想要的是读取512次1字节,然后你将得到字节数,所以交换buff_size1的位置。

附注:

  • 如果你在循环条件中正确检查,如:

    while ((bytes = fread(buff, 1, buff_size, fp)) > 0 )
    

    if (bytes > 0)的额外检查是多余的。

  • 写入时,您只想写入实际读取的字节数:

    fwrite(buff, 1, bytes, f);
    
  • 对于尺码,始终使用size_t - int很可能是错误的:

    size_t buff_size;
    size_t bytes;
    
  • 打印buff printf("%s", )未定义的行为,因为在{{1}读取数据后没有添加'\0'个字节}}。 C字符串必须以fread()结尾。如果'\0'读取的数据偶然不包含fread()'\0'将会读取并使用未初始化的数据,甚至可能超出printf()的范围。< / p>

答案 1 :(得分:1)

Felix Palmen在您的代码中列出了许多问题,您的修复完全错误,因为buff甚至没有空终结符。

这是一个更好的版本:

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

int main(void) {
    FILE *f, *fp;
    char buff[512];
    size_t bytes;

    fp = fopen("File.txt", "rb");
    if (fp == NULL) {
        fprintf(stderr, "Cannot open source file!\n");
        exit(1);
    }

    f = fopen("append.txt", "ab+");
    if (f == NULL) {
        fprintf(stderr, "Cannot open target file!\n");
        fclose(fp);
        exit(1);
    }

    while ((bytes = fread(buff, 1, sizeof buff, fp)) != 0) {
        if (fwrite(buff, 1, bytes, 1, f) != bytes) {
            fprintf(stderr, "Error writing to the target file\n");
            break;
        }
        printf("Appending...\n\n");
    }

    rewind(f);

    while ((bytes = fread(buff, 1, sizeof buff, f)) != 0) {
        printf("%.*s", (int)bytes, buff);
    }
    fclose(fp);
    fclose(f);
    return 0;
}

答案 2 :(得分:1)

bytes = fread(&buff, buff_size, 1, fp) > 0

看看C Precedence Chart。运算符>高于=,因此fread的返回值将与零进行比较,然后该比较的结果将存储在bytes中。你打算写这个

(bytes = fread(&buff, buff_size, 1, fp)) > 0

答案 3 :(得分:1)

给定固定文件名,这是我的问题解决方案。如果是我自己的代码,它会将文件名作为参数。

#include <stdio.h>

int main(void)
{
    const char src_file[] = "File.txt";
    FILE *fp = fopen(src_file, "rb");

    if (fp == NULL)
    {
        fprintf(stderr, "Cannot Open Source File '%s'!\n", src_file);
        return(1);
    }

    const char tgt_file[] = "append.txt";
    FILE *f = fopen(tgt_file, "ab+");

    if (f == NULL)
    {
        fprintf(stderr, "Cannot Open Target File '%s'!\n", tgt_file);
        fclose(fp);
        return(1);
    }

    char buff[512];
    int bytes;
    while ((bytes = fread(buff, sizeof(char), sizeof(buff), fp)) > 0)
    {
        fwrite(buff, sizeof(char), bytes, f);
        printf("Appending...\n\n");
    }

    rewind(f);

    while ((bytes = fread(buff, sizeof(char), sizeof(buff), f)) > 0)
        printf("%.*s", bytes, buff);

    fclose(fp);
    fclose(f);
    return 0;
}

有各种各样的修复方法,其中大多数都是在评论的某些地方明确表达的。

  • 我将文件名设置为数组,以便可以在fopen()和错误消息中使用该名称,这些消息打印到stderr,而不是stdout。这对于通用代码中的其他用户很有帮助。如果文件名来自命令行参数,则很简单。

  • fread()的调用是固定的,以便报告字节数,而不是512字节块的数量(将为0或1)。这涉及将大小/计数参数的顺序反转为fread()。传递缓冲区而不是缓冲区的地址。

  • 正确捕获读取的字节数。

  • 读取的字节数用于控制fwrite()的大小。

  • 读取的字节数用于控制printf()打印的字节数。

  • 我不喜欢C99及更高版本中的特殊规则允许main() - 但只有main() - 默认返回0。 AFAIAC,它是一个定义为返回int的函数;它应该返回int。但是,还有其他人不同意。