有关 C 语言拷贝文件的两种方式


前言

在 Unix 环境下进行文件的拷贝时遇到了一些问题,因此将两种方式都记录下来以备不时之需


一、通常拷贝方式

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

int main() {
	int i, ch;
	FILE *fp1, *fp2;
	
	char* from_file = "path\\to\\source\\file";
	char* to_file = "path\\to\\save\\file";

	fp1 = fopen(from_file, "r");
	fp2 = fopen(to_file, "w");

	if(fp1 != NULL && fp2 != NULL) {
		while((ch = fgetc(fp1)) != EOF) {
			fputc(ch, fp2);
		}
	} else {
		printf("failed to copy file due to open error");
	}

	fclose(fp1);
	fclose(fp2);
	return 0;
}

我们可以看到通常拷贝模式简单地打开了文件并且一个字节一个字节地将源文件中内容拷贝到目标文件中,并通过 EOF 标识符判定是否文件结束,而问题就恰恰出在了这里。

二、有关 EOF

EOFEnd Of File,标志着文件的结束,但它并不存在于文件中,即我们并不是通过读到文件中的 EOF 标志来判断文件是否结束。

EOF 本身是定义于 stdio.h 中的宏,值为 -1,相信看到这个值很多小伙伴应该就懂了,EOF 在拷贝的过程中相当于标志着读到的内容已经不在文件本身中了,通过报错实现了结束。但此时问题就来了 fgetc 返回的是 unsigned charEOF 的值为 -10xff,此时的判断根据编译结果或运行环境的不同将产生两种不同结果:

  1. fgetc 结果始终为 unsigned char, EOF 将被视为正常文件内容即 0xff 从而导致死循环
  2. fgetc 结果在与 EOF 比较时被提升为 int 型,EOF 正确识别并结束

作者最近正是遇到了第一种情况导致出现了很多问题,最后通过新的拷贝方式规避成功。

如果对比较时提升有疑虑的话可以试试以下代码

#include <stdio.h> 

int main(void)
{
  int i = -1;
  signed char sc = 0xff;
  unsigned char usc = 0xff;
    
  printf ("Comparing %x with %x\n", i, sc);
  if (i == sc)    puts("i == sc");
  else            puts("i != sc");
  putchar ('\n');
  printf ("Comparing %x with %x\n", i, usc);
  if (i == usc)   puts("i == usc");
  else            puts("i != usc");

  return 0;
}

/*
 * Output
 
 Comparing ffff with ffff     <--- Notice this has been promoted
 i == sc

 Comparing ffff with ff
 i != usc
 
 *
 */

三、新的拷贝方式

问题是找到了,那么怎么解决呢?答案很简单, 使读取后超出的错误能被正常比较捕捉即可。

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

int main() {
	int i, ch;
	size_t rs, ws;
	FILE *fp1, *fp2;
	
	char* from_file = "path\\to\\source\\file";
	char* to_file = "path\\to\\save\\file";

	fp1 = fopen(from_file, "rb");
	fp2 = fopen(to_file, "wb");

	if(fp1 != NULL && fp2 != NULL) {
		unsigned char buff[1024];
		do {
			rs = fread(buff, 1, sizeof(buff), fp1);
			if (rs) ws = fwrite(buff, 1, rs, fp2);
			else ws = 0;
		} while((rs >0) && (rs == ws));
	} else {
		printf("failed to copy file due to open error");
	}

	fclose(fp1);
	fclose(fp2);
	return 0;
}

参考资料

  1. EOF is not the end of the file
  2. Fgets,finding end of file without using eof feof
  3. Definition of EOF and how to use it effectively
  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值