您可以在文本模式下打开文件,在使用Visual Studio的Windows操作系统上,这涉及到非常重要的转换阶段,包括行尾转换.如果您的文件包含二进制内容,如可执行文件、图像和文档文件,则行尾转换会用CR LF对替换‘\n’字节,从而增加输出大小.
您可以通过以二进制模式打开包含"rb"
和"wb"
模式字符串的文件来避免此问题.
另请注意,假设文件支持查找且不大于LONG_MAX
(在Windows上仅为2 GB),则流必须以二进制模式打开ftell()
才能可靠地返回文件大小.对于POSIX系统,使用stat
从操作系统检索文件大小是一种更好的方法.一次复制一个块的文件也更可靠:它适用于不支持查找的流,并允许复制大于可用内存的文件.
以下是带错误判断的修改版本:
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
const char *inputfile = "test.txt";
const char *outputfile = "out.txt";
FILE *fp = fopen(inputfile, "rb");
if (fp == NULL) {
fprintf(stderr, "cannot open %s: %s\n", inputfile, strerror(errno);
return 1;
}
FILE *ofp = fopen(outputfile, "wb");
if (ofp == NULL) {
fprintf(stderr, "cannot open %s: %s\n", outputfile, strerror(errno);
return 1;
}
if (fseek(fp, 0, SEEK_END)) {
fprintf(stderr, "%s: cannot seek to the end of file: %s\n",
inputfile, strerror(errno);
return 1;
}
size_t fsize = ftell(fp);
char *buffer = calloc(fsize, 1);
if (buffer == NULL) {
fprintf(stderr, "cannot allocate %zu bytes: %s\n",
fsize, strerror(errno);
return 1;
}
rewind(fp);
size_t nread = fread(buffer, fsize, 1, fp);
if (nread != fsize) {
fprintf(stderr, "%s: read %zu bytes, file size is %zu bytes\n".
inputfile, nread, fsize);
}
size_t nwritten = fwrite(buffer, nread, 1, ofp);
if (nwritten != nread) {
fprintf(stderr, "%s: wrote %zu bytes, write size is %zu bytes\n".
outputfile, nwritten, nread);
}
fclose(fp);
if (fclose(ofp)) {
fprintf(stderr, "%s: error closing file: %s\n".
outputfile, strerror(errno));
}
free(buffer);
return 0;
}