提问人:dthnick 提问时间:10/28/2023 最后编辑:chqrliedthnick 更新时间:10/31/2023 访问量:71
为什么这个 while 循环在 C 中无法按预期工作
Why does this while loop not work as intended in C
问:
我正在尝试编写一个程序,该程序复制文件的内容,然后将内容放入另一个文件中。我的代码有效,但只复制一个字符。我认为我的循环是错误的,我不知道如何修复它。你可以帮我吗?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;
}
答:
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
函数使用的缓冲区的大小。使用至少与设置的缓冲区大小一样大的缓冲区绝对是一个好主意,假设使用长度为答案已修改。BUSIZ
BUFSIZ
<stdio.h>
fopen()
fopen
BUFSIZ
0赞
Luis Colorado
10/31/2023
您可以对这两个文件进行处理,如果它们具有相同的 和 .恕我直言,这在 POSIX 系统上足够可移植。这就是工具喜欢或检查的方式,以避免复制文件或在恢复备份时重新制作指向同一文件的链接。stat
st_dev
st_ino
tar(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
< 0
fwrite
// 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);
}
尽管您正在使用并调用双缓冲输入/输出,但使用单字节缓冲区会更简单:fread
fwrite
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 通常根据文件系统的最佳缓冲获得最佳缓冲区大小),您不必猜测它。
评论
fwrite
fclose