C语言中的文件复制函数

3
我尝试使用这个功能复制文件,但输出的文件包含了奇怪的字符。
int File_Copy (char FileSource [], char FileDestination [])
{
    int     result      =   -1;
    char    c [1];
    FILE    *stream_R   =   fopen (FileSource,      "r");
    FILE    *stream_W   =   fopen (FileDestination, "w");   //create and write to file

    while ((c [0] = (char) fgetc(stream_R)) != EOF)
    {
        fprintf (stream_W, c);
    }

    //close streams
    fclose  (stream_R);
    fclose  (stream_W);

    return result;
}

我不知道出了什么问题,请帮忙。


fgetc() 返回一个 int 类型的值。将其转换为 char 会丢失信息。 - pmg
2个回答

7
问题在于c[1]作为字符串无法工作,因为它不能包含终止的nul字节,所以应该是:
char c[2] = {0};

而且,c [2] 应该是 int 类型,像这样:

int c[2] = {0};

由于fgetc()返回的是int类型,所以您的代码有可能会溢出c[0],但是您还有其他可以改进的地方。

  1. You don't need c to be an array, you can just declare it like this.

    int c;
    

    and then use fputc(); instead of fprintf().

  2. You must check that none of the fopen() calls failed, otherwise your program will invoke undefined behavior because of NULL pointer dereference.

这是一个强大的版本,修复了您在问题中描述的程序问题。
/*   ** Function return value meaning
 * -1 cannot open source file 
 * -2 cannot open destination file
 * 0 Success
 */
int File_Copy (char FileSource [], char FileDestination [])
{
    int   c;
    FILE *stream_R;
    FILE *stream_W; 

    stream_R = fopen (FileSource, "r");
    if (stream_R == NULL)
        return -1;
    stream_W = fopen (FileDestination, "w");   //create and write to file
    if (stream_W == NULL)
     {
        fclose (stream_R);
        return -2;
     }    
    while ((c = fgetc(stream_R)) != EOF)
        fputc (c, stream_W);
    fclose (stream_R);
    fclose (stream_W);

    return 0;
}

我最初将其设置为int类型。然而,fprintf()函数需要const char[]类型,例如--> int fprintf(FILE *stream, const char formatString[], ...)。我使用它时出现了致命的运行时错误。我该怎么办? - CaTx
@CaTx 但是你不需要使用 fprintf() 来写入单个字符。 - Iharob Al Asimi
我应该使用什么替代方案? - CaTx

6

您为什么要一次复制一个字节呢?那样会非常慢!虽然您的主要问题可能是使用了fprintf(),而printf()函数旨在打印格式化字符串,而不是单个字符。

如果您只是将字节从一个文件传输到另一个文件,则应改用fread和fwrite,如下所示:

int File_Copy(char FileSource[], char FileDestination[])
{
    char    c[4096]; // or any other constant you like
    FILE    *stream_R = fopen(FileSource, "r");
    FILE    *stream_W = fopen(FileDestination, "w");   //create and write to file

    while (!feof(stream_R)) {
        size_t bytes = fread(c, 1, sizeof(c), stream_R);
        if (bytes) {
            fwrite(c, 1, bytes, stream_W);
        }
    }

    //close streams
    fclose(stream_R);
    fclose(stream_W);

    return 0;
}

我不知道其他的函数。您的方法似乎对文件大小(c[]的大小)有限制。有没有一种方法可以修改它以消除这个限制? - CaTx
这个版本更快,因为它一次读取4096个字节。如果你想一次读取1个字节,那么将4096改为1。此外,需要进行I/O错误处理,就像iharob的回答中所述。 - Barmak Shemirani
@CaTx 文件大小没有限制。代码每次循环复制4096个字节,直到所有数据都被复制。这比逐字节复制要快一些,代价是稍微多一点的内存使用(但现在4 KB算什么呢?) - Enno

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接