函数声明:
size_t fread(void *buf, sizeof(void), len, FILE *p);
解释:
sizeof( void ) 和 len 是搭配使用的,它们的作用就是令临时空间使用完:
char a = 0;
fread(&a, 1, 1, p);
//一次使用完
char b[10] = { 0 };
fread(b, sizeof(char), sizeof(b), p);
//每次读取一个char 读取10次。
char c[10] = { 0 };
fread(c, 1, 1, p);
返回值:
fread 的返回值是每次从p中读取的数据的个数,也就是len 的值。
函数声明:
size_t fwrite(void *buf, sizeof(void), int nums, FILE *p);
解释:
fwrite的使用于fread是相互映照的。
返回值:
返回每次写入的次数。
mycopy.c :
#include <stdio.h>
void mycopy(char *str1, char *str2)
{
FILE *p = fopen(str1, "rb");
FILE *p1 = fopen(str2, "wb");
unsigned int index = 0; //统计复制了多少次
while(1)
{
char buf[1024] = { 0 };
fread(buf, sizeof(char), 1024, p);
if(feof(p))
break;
fwrite(buf, sizeof(char), 1024, p1);
index++;
}
fclose(p);
fclose(p1);
printf("%d\n", index);
}
int main(int arge, char **arges)
{
if(arge < 3)
return 0;
mycopy(arges[1], arges[2]);
return 0;
}
解析:
上述代码主要通过一个1kB的空间来实现缓存区,通过缓存区把一个文件的数据读出来,然后把数据写入要复制的文件内。
#编译
gcc -o a mycopy.c
#运行
#把a.txt 复制一份为b.txt
a test1.mp4 test2.mp4
运行结果:
通过运行得到以下下文件
[使用fread和fwrite实现文件拷贝]$ ll
total 21573
-rwxr-xr-x 1 Administrator 197121 55425 三月 21 16:00 a.exe*
-rw-r--r-- 1 Administrator 197121 555 三月 21 18:53 mycopy.c
-rw-r--r-- 1 Administrator 197121 11014383 一月 14 2017 test1.mp4
-rw-r--r-- 1 Administrator 197121 11014144 三月 21 18:59 test2.mp4
#可以看到文件小于原文件的大小。
上述代码虽然可以把文件给复制下来,但还不能完美的复制下来,test2.mp4 尾数是144,test1.mp4 尾数是383,明显比原文件小。
错误原因:
每次都要往文件中写入1024个,最后一次会读取到文件末尾,跳出循环,不够1024会舍弃数据。
测试代码:
创建一个a.txt
abcde
文件有5个字节的空间
-rw-r--r-- 1 Administrator 197121 5 三月 21 19:15 a.txt
代码
void mycopy_test(char *str1, char *str2)
{
FILE *p = fopen(str1, "rb");
FILE *p1 = fopen(str2, "wb");
unsigned int index = 0;
while(1)
{
char buf[10] = { 0 };
fread(buf, sizeof(char), 3, p);//每次只读3个字节的空间
if(feof(p))
break;//当读取到文件末尾不够3个字节时,也就是fread和3不相等,会跳出循环。
fwrite(buf, sizeof(char), 3, p1);
index++;
}
fclose(p);
fclose(p1);
printf("%d\n", index);
}
当最后读取空间不够时,会跳出循环。
改进后代码:
void mycopy_test(char *str1, char *str2)
{
FILE *p = fopen(str1, "rb");
FILE *p1 = fopen(str2, "wb");
unsigned int index = 0;
while(!feof(p))
{
char buf[10] = { 0 };
fread(buf, sizeof(char), 3, p);
fwrite(buf, sizeof(char), 3, p1);
index++;
}
fclose(p);
fclose(p1);
printf("%d\n", index);
}
改进后的代码,最后读出不够3个字节,“abcde” ,只读出了2个字节,然后写入到文件b.txt中。
测试结果:
[使用fread和fwrite实现文件拷贝]$ ll
total 21582
-rwxr-xr-x 1 Administrator 197121 55967 三月 21 19:28 a.exe*
-rw-r--r-- 1 Administrator 197121 5 三月 21 19:15 a.txt
-rw-r--r-- 1 Administrator 197121 6 三月 21 19:28 b.txt
-rw-r--r-- 1 Administrator 197121 910 三月 21 19:28 mycopy.c
可以看到b.txt文件比原文件又大了一个字节。
所以我们找到了第二个错误,写入字节没控制好。
解决方法:通过设置读文件字节的返回值,来设置写文件的次数。
代码实现:
void mycopy_test(char *str1, char *str2)
{
FILE *p = fopen(str1, "rb");
FILE *p1 = fopen(str2, "wb");
unsigned int index = 0;
while(!feof(p))
{
char buf[10] = { 0 };
int res = fread(buf, sizeof(char), 3, p);
fwrite(buf, sizeof(char), res, p1);
index++;
}
fclose(p);
fclose(p1);
printf("%d\n", index);
}
res 是 fread 读出1个字节的次数,然后把它设为写入1个字节的次数,这样就不会复制失败任何一个字节。
当我们发现我们可以通过设置临时空间来实现文件的复制的时候,我们会非常高兴,但当一个文件非常小的时候,我们设置了一个非常大的临时空间,这就浪费了内存;当文件非常大的时候,我们设计了一个非常小的临时空间,我们函数的循环的时间久会变长,也是非常难受,那有没有一种非常好的方法,每次用多少内存就开辟多少的临时空间呢?
当然是有的!
我们可以通过使用stat函数来获取文件的字节大小,根据文件的大小开辟对应的内存空间,并合理的规划文件的拷贝次数,从而达到文件被拷贝的目的。
#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>
#define NUM 1024 * 10 //10KB
void mycopy_dynamic(char *str1, char *str2)
{
FILE *p = fopen(str1, "rb");
FILE *p1 = fopen(str2, "wb");
struct stat st = { 0 };
stat(str1, &st);
int size = st.st_size;
if(size >= NUM)
size = NUM;
char *buffer = malloc(size);
unsigned int index = 0;
while(!feof(p))
{
int res = fread(buffer, sizeof(char), size, p);
fwrite(buffer, sizeof(char), res, p1);
index++;
}
free(buffer);
fclose(p);
fclose(p1);
printf("%d\n", index);
}
int main(int arge, char **arges)
{
if(arge < 3)
return 0;
mycopy_dynamic(arges[1], arges[2]);
return 0;
}
通过上述代码,我们实现了每次拷贝不超过10KB的文件一次拷贝完的操作,如果文件大于10KB,就只申请10KB的内存空间,实现了动态开辟内存来存储临时数据。
[使用fread和fwrite实现文件拷贝]$ a test1.mp4 test2.mp4
1076
[使用fread和fwrite实现文件拷贝]$ ll
total 21586
-rwxr-xr-x 1 Administrator 197121 57451 三月 22 15:20 a.exe*
-rw-r--r-- 1 Administrator 197121 5 三月 21 19:15 a.txt
-rw-r--r-- 1 Administrator 197121 6 三月 21 19:28 b.txt
-rw-r--r-- 1 Administrator 197121 1593 三月 22 15:22 mycopy.c
-rw-r--r-- 1 Administrator 197121 11014383 一月 14 2017 test1.mp4
-rw-r--r-- 1 Administrator 197121 11014383 三月 22 15:24 test2.mp4