文件复制,首先要知道被复制的文件的大小,可以用 fseek 将文件指针定位到文件尾部SEEK_END,再用 ftell 来取得文件大小,注意,这个返回值单位是 字节 ,即 char 的大小,还有就是别忘了ftell之后再次用 fseek 来将文件指针定位到文件起始处 SEEK_SET。取得文件大小后,我们就可以在堆中分配一块内存空间来做为一个buffer。这里之所以用堆,是因为栈的容量是实在有限,再加上实际上栈的容量是可以人为的调配的,所以最好用堆。但我在VS2005+win7的环境中分配4M大小的栈,是没有问题的。最后,我们再用fread fwrite通过一次或几次来做文件复制。
为什么是“一次或几次”呢?因为我们的内存是有限的。比如我现在这台电脑上的内存就只有2G,现在空闲的不到1.3G,如果要复制一个3G的文件,分配一块内存,最多也就分配1.3G不到,一次是不可能复制完的。所以遇到这种怀况就要分几次来完成。
还有一种不必计算文件大小的方法即用 while(!feof(fin)) { fputc(fgetc(fin),fout);} 来做,只是这个很耗时间。我用两种方法复制一个1.8M不到的文件,前一种方法是20ms,后面这种竟然要650ms。
还要记住的是buffer的大小问题。计算机一个磁道的大小是4M,C/C++输入输出流的buffer大小也是4M。所以,在自己定义文件buffer的时候,最好分配4096个字节。谢谢QQ群26367769里“恺撒之悲伤”的帮助,这个是他告诉我的。唉,只怪自己书读得少啊。
附源完整代码:
#include <cstdio>
#include <cstdlib> //调用 system()方法的时候要用到
#include <ctime>
//参数2是源文件,参数3是复制所得文件
int main(int argc,char* argv[])
{
if(argv[1] && argv[2])
{
clock_t start,end;
start = clock();
FILE* fsrc;
fsrc = fopen(argv[1],"rb");
if(!fsrc)
{
printf("can't open your src file\n");
return 1;
}
fseek(fsrc,0,SEEK_END);
long filesize = ftell(fsrc);
printf("the src file's size is %d M\n",filesize/(1024*1024));
fseek(fsrc,0,SEEK_SET); //这个很重要,要把文件指针重新定位到文件开头
FILE* fdest;
fdest = fopen(argv[2],"ab");
if(!fdest)
{
printf("can't create your dest file\n");
return 1;
}
if(filesize>4096)//如果4M以上就分次复制
{
int n = filesize/4096;// n 块
int leavesize = filesize%4096;
char* buf = new char[4096];
for(int i=0;i<n;i++)
{
fread(buf,sizeof(char),4096,fsrc);
fwrite(buf,sizeof(char),4096,fdest);
}
fread(buf,sizeof(char),leavesize,fsrc);
fwrite(buf,sizeof(char),leavesize,fdest);
delete buf;
buf = 0;
}
else //否则直接复制
{
char* buf = new char[filesize];
fread(buf,sizeof(char),filesize,fsrc);
fwrite(buf,sizeof(char),filesize,fdest);
delete buf;
buf = 0;
}
fseek(fdest,0,SEEK_END);
long filesize2 = ftell(fdest);
printf("the dest file's size is %d M\n",filesize2/(1024*1024));
fclose(fdest);
fclose(fsrc);
end = clock();
printf("the duration is %f S\n ",(double)(end - start)/1000);
}
else
printf("no file\n");
system("pause");
return 0;
}