为什么这个 while 循环在 C 中无法按预期工作

Why does this while loop not work as intended in C

提问人:dthnick 提问时间:10/28/2023 最后编辑:chqrliedthnick 更新时间:10/31/2023 访问量:71

问:

我正在尝试编写一个程序,该程序复制文件的内容,然后将内容放入另一个文件中。我的代码有效,但只复制一个字符。我认为我的循环是错误的,我不知道如何修复它。你可以帮我吗?while

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

int main(int argc, char *argv[]) {
    // Check if the user provided exactly two filenames
    if (argc != 3) {
        printf("Usage: %s [source_file] [destination_file]\n", argv[0]);
        return 1;  // Return an error code to indicate failure
    }

    // Open the source file for reading
    FILE *source = fopen(argv[1], "rb");

    if (source == NULL) {
        printf("Error: Unable to open the source file.\n");
        return 1;
    }

    // Open the destination file for writing
    FILE *destination = fopen(argv[2], "wb");

    if (destination == NULL) {
        printf("Error: Unable to open the destination file.\n");
        fclose(source); // Close the source file before exiting
        return 1;
    }

    char buffer[1024];
    size_t bytes_read;

    // Copy the contents of the source file to the destination file
    while ((bytes_read = fread(buffer, 1, sizeof(buffer), source)) > 0) {
        fwrite(buffer, 1, bytes_read, destination);
    }

    // Close both files
    fclose(source);
    fclose(destination);

    printf("File copied successfully.\n");
    return 0;
}
C 文件 while 循环 复制

评论

0赞 Ted Lyngmo 10/28/2023
我认为除了你的程序之外,还有其他东西出了问题。你的程序为我做了一个完美的副本。也检查 和 s 的返回值。也许它出于某种原因写“短”。fwritefclose
1赞 Fe2O3 10/28/2023
在重新编译之前是否保存了此版本?您可能正在执行不正确的源代码的早期版本。
0赞 dthnick 10/28/2023
就是这样,非常感谢!!
0赞 Fe2O3 10/28/2023
不用担心。现在每个人都会遇到这种情况,因为这些现代 IDE 允许每个职业出租车司机和服务生编写代码......

答:

0赞 chqrlie 10/28/2023 #1

发布的代码没有问题。程序应将名称指定为第一个参数的文件复制到名称指定为第二个参数的新文件中,如果该文件已存在,则将创建或截断该文件。唯一需要注意的是,如果程序使用与源和目标相同的文件运行:文件将在读取其内容之前被截断,从而导致数据丢失。

问题出在别处......

如果同一个文件是不同的字符串,则无法通过可移植的方法来判断它们是否和命名它们,但可以实现一些其他改进,例如更明确的错误消息:argv[1]argv[2]

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

int main(int argc, char *argv[]) {
    int status = 0;

    // Check if the user provided exactly two filenames
    if (argc != 3) {
        printf("Usage: %s [source_file] [destination_file]\n", argv[0]);
        return 1;  // Return an error code to indicate failure
    }

    // Open the source file for reading
    FILE *source = fopen(argv[1], "rb");
    if (source == NULL) {
        fprintf(stderr, "Error: Unable to open the source file %s: %\n",
                argv[1], strerror(errno));
        return 1;
    }

    // Open the destination file for writing
    FILE *destination = fopen(argv[2], "wb");
    if (destination == NULL) {
        fprintf(stderr, "Error: Unable to open the destination file %s: %s\n",
                argv[2], strerror(errno));
        fclose(source); // Close the source file before exiting
        return 1;
    }

    char buffer[BUFSIZ > 1024 ? BUFSIZ : 1024];
    size_t bytes_read;

    // Copy the contents of the source file to the destination file
    while ((bytes_read = fread(buffer, 1, sizeof(buffer), source)) > 0) {
        size_t bytes_written = fwrite(buffer, 1, bytes_read, destination);
        if (bytes_written != bytes_read) {
            fprintf(stderr, "Error: cannot write %zu bytes\n",
                    bytes_read - bytes_written);
            status = 1;
            break;
        }
    }

    // Close both files
    fclose(source);
    if (fclose(destination)) {
        fprintf(stderr, "Error: closing file %s failed: %s\n",
                argv[2], strerror(errno));
        status = 1;
    }

    if (!status) {
        printf("File copied successfully.\n");
    }
    return status;
}

评论

1赞 chqrlie 10/28/2023
@Fe2O3:使用确实可以优化吞吐量,但 C 标准没有这样的保证。它仅指定BUFSIZ 的值应至少为 256,并且 中定义 扩展为整数常量表达式,该表达式是 setbuf 函数使用的缓冲区的大小。使用至少与设置的缓冲区大小一样大的缓冲区绝对是一个好主意,假设使用长度为答案已修改。BUSIZBUFSIZ<stdio.h>fopen()fopenBUFSIZ
0赞 Luis Colorado 10/31/2023
您可以对这两个文件进行处理,如果它们具有相同的 和 .恕我直言,这在 POSIX 系统上足够可移植。这就是工具喜欢或检查的方式,以避免复制文件或在恢复备份时重新制作指向同一文件的链接。statst_devst_inotar(1)cpio(1)
0赞 chqrlie 10/31/2023
@LuisColorado:是的,这种方法在POSIX系统上是经典的,但在Windows或其他系统上不起作用。因此,我的这句话没有便携的方法......
0赞 Luis Colorado 10/31/2023 #2

你对所有预处理函数中的错误进行全面检查有点奇怪,但试想一下,循环中调用的所有例程都正常工作。

    char buffer[1024];
    size_t bytes_read;

    // Copy the contents of the source file to the destination file
    while ((bytes_read = fread(buffer, 1, sizeof(buffer), source)) > 0) {
        fwrite(buffer, 1, bytes_read, destination);
    }

您应该考虑返回的可能性(这是一个错误,如果您从套接字或设备读取数据,有时会发生这种情况)并检查 的结果代码。更好的方法可能是:fread< 0fwrite

    // Copy the contents of the source file to the destination file
    while ((bytes_read = fread(buffer, 1, sizeof(buffer), source)) > 0) {
        ssize_t written = fwrite(buffer, 1, bytes_read, destination);
        if (written < 0) {
            fprintf(stderr, "fwrite error: %s\n", strerror(errno));
            exit(1);
        }
        if (written < bytes_read) {
            fprintf(stderr, "partial write\n");
            exit(1);
        }
    }
    if (bytes_read < 0) {
         fprintf(stderr, "fread error: %s\n", strerror(errno));
         exit(1);
    }

尽管您正在使用并调用双缓冲输入/输出,但使用单字节缓冲区会更简单:freadfwrite

    int c;
    while ((c = fgetc(source)) != EOF) {
        if ((c = fputc(c, destination)) == EOF)
            break;
    }
    if (ferror(source)) {
        // error on reading source
    }
    if (ferror(destination)) {
        // error on writing destination
    }

这将使用最佳缓冲区大小(STDIO 通常根据文件系统的最佳缓冲获得最佳缓冲区大小),您不必猜测它。