大文件拷贝

准备一个几百兆的稍大点的文件。比如视频文件。我这里是298MB的一个文件:

按照逐字节拷贝

注意对非文本文档读写,要带‘b’,此外,对于非文本文档结尾的判断应使用feof()函数,而非eof。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(int argc, char* argv[])
{
	unsigned int start_time = time(NULL);
	FILE* fpr = fopen("F:/Practice/1.mp4", "rb");
	FILE* fpw = fopen("F:/Practice/2.mp4", "wb");
	if (!fpr || !fpw)
	{
		printf("操作文件操作。");
		return -2;
	}
	char ch;
	while (!feof(fpr))
	{
		ch = fgetc(fpr);
		fputc(ch, fpw);
	}
	fclose(fpr);
	fclose(fpw);
	unsigned int end_time = time(NULL);
	printf("运行时间:%d(s)\n", end_time - start_time);  // 48秒
	
	getchar();
	return 0;
}

 结果发现大小多了个字符。用时48秒。



按照逐行拷贝。

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

int main(int argc, char* argv[])
{
	unsigned int start_time = time(NULL);
	FILE* fpr = fopen("F:/Practice/1.mp4", "rb");
	FILE* fpw = fopen("F:/Practice/3.mpr", "wb");
	if (!fpr || !fpw)
	{
		printf("打开文件错误。\n");
		return -1;
	}
	char ch[1024];
	while (!feof(fpr))
	{
		// 未防止最后不足1024而污染最后一个1024.所以需要将其重置。
		memset(ch, 0, 1024);
		fgets(ch, 1024, fpr);
		fputs(ch, fpw);
	}

	fclose(fpr);
	fclose(fpw);
	unsigned int end_time = time(NULL);
	printf("运行时间:%d(s)\n", end_time - start_time);

	getchar();
	return 0;
}

运行时间:7s。速度提升了7倍。

然后看大小。

 文件大小少了一半,无法打开观看。



按照逐块拷贝

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//#include <stdlib.h>


int main(int argc, char* argv[])
{
	unsigned int start_time = time(NULL);
	FILE* fpr = fopen("F:/Practice/1.mp4", "rb");
	FILE* fpw = fopen("F:/Practice/4.mp4", "wb");
	if (!fpr || !fpw)
	{
		printf("文件打开失败。\n");
		return -1;
	}
	char ch[1024];
	while (!feof(fpr))
	{
		memset(ch, 0, 1024);
		fread(ch, 1024, 1, fpr);
		fwrite(ch, 1024, 1, fpw);
	}

	fclose(fpr);
	fclose(fpw);
	unsigned int end_time = time(NULL);
	printf("运行时间:%d(s)\n", end_time - start_time);

	getchar();
	return -1;
}

程序运行时间1s。速度提升了四十多倍。 

但是文件与源文件大小并不一致。312966144字节。 = 305631 * 1024。也就是说是1024的整数倍。

 为什么如此呢?

因为最后一个1024,源内容没有填满,最后1024也填满了0,将0写入了新文件中。所以大了小于1024个字节。


解决方案:

 我们来看一下读取函数:第二个参数为:块大小。第三个参数为块数。

重点是返回值:

  • 如果读取成功:返回实际读成功的块数。如果这个值小于nmemb这个设定块数。则说明读到了结尾。
  • 失败:返回0,没读到东西。

 基于此改进方案:读取的时候:size设置为1;块数设置为1024。返回值如果小于1024,则终止程序,并在写入是,写入读取到的个数,而不是原来的1024个。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>


int main(int argc, char* argv[])
{

	unsigned int start_time = time(NULL);
	FILE* fpr = fopen("F:/Practice/1.mp4", "rb");
	FILE* fpw = fopen("F:/Practice/5.mp4", "wb");

	if (!fpr || !fpw)
	{
		printf("打开文件出错.");
		return -1;
	}

	char ch[1024];
	int rNum = 0;
	while (!feof(fpr))
	{
		memset(ch, 0, 1024);
		rNum = fread(ch, 1, 1024, fpr);
		if (rNum == 1024)  // 这个可以优化掉。
		{
			fwrite(ch, 1, rNum, fpw);
		}
		else// 多余可以优化。
		{
			fwrite(ch, 1, rNum, fpw);
			break;
		}
	}
	fclose(fpr);
	fclose(fpw);
	unsigned int end_time = time(NULL);
	printf("运行时间:%d(s)\n", end_time - start_time);

	getchar();
	return -1;
}

至此:复制之后,大小完全一样。文件可以正常打开。



还可以再优化的地方

现在每次读取是1024字节,也就是1KB,我们把它改成1MB。那么此时就不能在栈中直接开辟空间了,就需要到堆中开辟空间。malloc。

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


int main(int argc, char* argv[])
{
	unsigned int start_time = time(NULL);
	FILE* fpr = fopen("F:/Practice/1.mp4", "rb");
	FILE* fpw = fopen("F:/Practice/6.mp4", "wb");

	if (!fpr || !fpw)
	{
		printf("打开文件错误。");
		return -1;
	}

	//char ch[1024];
	char* ch = (char*)malloc(sizeof(char) * 1024 * 1024);
	int rNum = 0;
	while (!feof(fpr))
	{
		memset(ch, 0, 1024 * 1024);
		rNum = fread(ch, 1, 1024 * 1024, fpr);
		fwrite(ch, 1, rNum, fpw);
	}
	fclose(fpr);
	fclose(fpw);
	free(ch);
	ch = NULL;
	unsigned int end_time = time(NULL);
	printf("运行时间:%d(s)\n", end_time - start_time);
	getchar();
	return -1;
}

用time()函数来统计时间只能到秒。需用用到clock相关函数统计到ms。    

clock_t StartTime, EndTime;

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>



int main(int argc, char* argv[])
{
	unsigned int start_time = time(NULL);
	clock_t StartTime, EndTime;
	StartTime = clock();
	
	FILE* fpr = fopen("F:/Practice/1.mp4", "rb");
	FILE* fpw = fopen("F:/Practice/6.mp4", "wb");

	if (!fpr || !fpw)
	{
		printf("打开文件错误。");
		return -1;
	}

	//char ch[1024];
	char* ch = (char*)malloc(sizeof(char) * 1024 * 1024);
	int rNum = 0;
	while (!feof(fpr))
	{
		//memset(ch, 0, 1024);
		memset(ch, 0, 1024 * 1024);
		rNum = fread(ch, 1, 1024 * 1024, fpr);
		fwrite(ch, 1, rNum, fpw);
	}
	fclose(fpr);
	fclose(fpw);
	free(ch);
	//ch = NULL;
	unsigned int end_time = time(NULL);
	EndTime = clock();
	printf("运行时间:%d(ms)\n", EndTime - StartTime);
	
	getchar();
	return -1;
}

如果放在栈中char ch[1024]:时间为:919ms

改为1024乘以1024:1MB,且放入堆中之后时间为151ms

如果改为10MB,看看效果:180ms。并没有提升。1MB最佳。



还可以优化的点

将fwrite的第二个与第三个参数互换,时间提高到130ms。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>



int main(int argc, char* argv[])
{
	unsigned int start_time = time(NULL);
	clock_t StartTime, EndTime;
	StartTime = clock();
	
	FILE* fpr = fopen("F:/Practice/1.mp4", "rb");
	FILE* fpw = fopen("F:/Practice/6.mp4", "wb");

	if (!fpr || !fpw)
	{
		printf("打开文件错误。");
		return -1;
	}

	//char ch[1024];
	char* ch = (char*)malloc(sizeof(char) * 1024 * 1024);
	int rNum = 0;
	while (!feof(fpr))
	{
		//memset(ch, 0, 1024);
		//memset(ch, 0, 1024 * 1024);
		rNum = fread(ch, 1, 1024 * 1024, fpr);
		//fwrite(ch, 1, rNum, fpw);// 写入块数可以大一点。第2与第3参数互换。
		fwrite(ch, rNum, 1, fpw);// 写入块数可以大一点。第2与第3参数互换。

	}
	fclose(fpr);
	fclose(fpw);
	free(ch);
	//ch = NULL;
	unsigned int end_time = time(NULL);
	EndTime = clock();
	printf("运行时间:%d(ms)\n", EndTime - StartTime);
	
	getchar();
	return -1;
}

还有没有优化的空间?

根据文件的状态参数来设置复制的块数和size大小。精准控制。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>

#define MAXSIZE 1024 * 1024

int main(int argc, char* argv[])
{
	clock_t StartTime, EndTime;
	StartTime = clock();

	FILE* fpr = fopen("F:/Practice/1.mp4", "rb");
	FILE* fpw = fopen("F:/Practice/7.mp4", "wb");
	if (!fpr || !fpw)
	{
		printf("打开文件错误。");
		return -1;
	}
	// 获取文件状态。
	struct stat s;
	stat("F:/Practice/1.mp4", &s);  // 通过结构体获取文件状态。
	//printf("文件字节大小:%d Bytes\n", s.st_size);
	//char ch[1024];
	char* ch;
	int maxSize = 0;
	if (s.st_size < MAXSIZE)
	{
		maxSize = s.st_size;
		ch = (char*)malloc(sizeof(char) * s.st_size);
	}
	else
	{
		maxSize = MAXSIZE;
		ch = (char*)malloc(sizeof(char) * MAXSIZE);
	}
	int rNum = 0;
	while (!feof(fpr))
	{
		//memset(ch, 0, 1024 * 1024);  // 我个人感觉可以不用。因为是指定数量的写入。当然,严谨点可以写上。
		rNum = fread(ch, 1, maxSize, fpr);
		//fwrite(ch, 1, rNum, fpw);// 写入块数可以大一点。第2与第3参数互换。
		fwrite(ch, rNum, 1, fpw);// 写入块数可以大一点。第2与第3参数互换。严进宽出。

	}
	fclose(fpr);
	fclose(fpw);
	free(ch);
	EndTime = clock();
	printf("运行时间:%d(ms)\n", EndTime - StartTime);

	getchar();
	return 0;
}

运行时间:184ms。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值