1. 采用读一个字符和写一个字符的相关函数复制文件
注意点一:判断目标文件是否打开的前提是,源文件已经可以正常打开了。如果目标文件打开失败,需要将源文件的文件流关闭,以免消耗系统资源。
注意点二:函数 ferror()的用法。先利用 getc() 函数读取字符,获得其返回值。若返回值为 EOF,则判断 EOF 的原因是正常读取结束还是读取失败。ferror() 函数接收文件流参数,如果返回值非 0,说明读取失败。
注意点三:通常,写入文件的返回值不会为 EOF,原因在于文件可以无限写下去。一旦返回 EOF,则说明文件写入失败。
此方法的缺点是每次只读一个字符,速度过慢,通常应该借助缓冲区批量读取和写入。
#include <stdio.h>
// 定义七种情况
#define COPY_SUCCESS 0
#define COPY_ILLEGAL_ARGUMENTS -1 // 参数非法
#define COPY_SRC_OPEN_ERROR -2 // 源文件打开失败
#define COPY_SRC_READ_ERROR -3 // 源文件读取失败
#define COPY_DEST_OPEN_ERROR -4 // 目标文件打开失败
#define COPY_DEST_WRITE_ERROR -5 // 目标文件写入失败
#define COPY_UNKNOWN_ERROR -100 // 未知错误
int CopyFile(char const *src, char const *dest){
// 如果传入参数有一个为空
if(src == NULL || dest == NULL){ // if(!src || !dest)
return COPY_ILLEGAL_ARGUMENTS;
}
FILE *src_file = fopen(src, "r");
// 源文件没能打开
if(src_file == NULL){
return COPY_SRC_OPEN_ERROR;
}
// 源文件此时打开,开始目标文件的操作
FILE *dest_file = fopen(dest, "w");
// 目标文件没能打开
if(dest_file == NULL){
// 这里有个坑,源文件此时是打开的,需要关闭源文件
fclose(src_file);
return COPY_DEST_OPEN_ERROR;
}
// 此时进行文件复制操作
int result;
while(1){
// 读的过程
int src_input = getc(src_file);
if(src_input == EOF){ // 读取到结束标志
// 判断是哪种原因导致文件读取结束
if(ferror(src_file)){ // 结果非0,说明源文件读取失败
result = COPY_SRC_READ_ERROR;
}else if(feof(src_file)){ // 源文件是正常读取结束
result = COPY_SUCCESS;
}else{ // 其余错误
result = COPY_UNKNOWN_ERROR;
}
break; // 结束标志之后,退出此循环
}
// 写的过程
// 通常文件可以无限写下去,即正常复制文件后,返回值不会是 EOF
// 一旦返回 EOF 说明写入失败,直接停止。此处不需要判断哪种原因导致写入失败
if(putc(src_input, dest_file) == EOF){
result = COPY_DEST_WRITE_ERROR;
break;
}
}
// 不要忘记关闭两个文件流
fclose(src_file);
fclose(dest_file);
return result;
}
int main() {
int result = CopyFile("main.c", "01.c");
printf("result: %d", result);
return 0;
}