用C语言、系统IO实现文件复制(带进度条)
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#define SIZE 50 //堆或者数组buffer的大小
#define W_BUF_SIZE 100 //文件复制过程中,设置写入缓冲区字节大小
int main(int argc, const char* argv[])
{
/* //0.选择源文件、目标文件 */
//输入src_file绝对路径名
printf("pls input src_file_path: ");
char *src_file=malloc(SIZE);
bzero(src_file,SIZE);
scanf("%s",src_file);while(getchar()!='\n');
printf("src_file : %s\n",src_file);
//输入des_file绝对路径名
printf("pls input des_file_path: ");
char *des_file=malloc(SIZE);
bzero(des_file,SIZE);
scanf("%s",des_file);while(getchar()!='\n');
printf("des_file : %s\n",des_file);
/* //1.只读方式打开源文件、只写和创建方式打开目标文件 */
int fd_src=open(src_file, O_RDONLY);
printf("fd_src=%d\n",fd_src);
printf("src_file : %s\n",src_file);
if(fd_src==-1)
{
perror("Open src_file failed or isn't exist!!!\n");
return -1;
}
int fd_des=open(des_file, O_WRONLY|O_CREAT|O_TRUNC,0755);
if(fd_des!=-1)
{
printf("Open des_file successfully!\n");
}else
{
perror("Open des_file failed!!!\n");
return -2;
}
/* //2.读取源文件内容,同时写入目标文件和显示进度条,直到读取完毕 */
char *buf=malloc(W_BUF_SIZE);
int n_read, n_write; //已读取字节数、已写入字节数
double persent; //复制进度的百分比变量,小数形式
//将源文件偏移量移动到末尾,lseek函数返回源文件总字节数
//定义成double类型,方便之后除法得到小数形式的百分比
double src_total_bytes=lseek(fd_src,0,SEEK_END);
if(src_total_bytes!=-1)
{
printf("src_total_bytes = %.2lf(bytes)\n",src_total_bytes);
}else
{
perror("Illegal src_total_bytes!!!\n");
}
lseek(fd_src,0,SEEK_SET); //修改偏移量至文件开始位置
lseek(fd_des,0,SEEK_SET);
printf("Copying start...:\n");
while(1)
{
bzero(buf,W_BUF_SIZE); //清空buffer
n_read=read(fd_src,buf,W_BUF_SIZE); //每次读取SIZE个字节数
if(!n_read) break; //如果读取字节数为0,说明读取完毕
//将每次读取的内容写入标文件,注意如果读取到0('\0'),
//就不能使用strlen计算大小,直接使用n_read即可
n_write=write(fd_des,buf,n_read);
//计算进度百分比,小数形式
persent=lseek(fd_des, 0, SEEK_CUR)/src_total_bytes;
//打印本次读取字节数、写入字节数、小数形式进度百分比
printf(" Get(%3d B), %3d bytes written! persent = %lf\n",
n_read,n_write,persent);
//刷新展示百分比进度条,样式:[#######]80%...|
int i;
const char* label="|/-\\"; //复制进度条最后面的字符旋转动画
static int index=0; //label字符串的下标,声明为静态变量,在while代码块作用域内,只能赋值一次了
int persent_counts=persent*100; //将小数形式百分比转换为整数形式,方便后面控制刷新进度条长度
printf("[");
//当进度百分比(整数形式)前进10个点时,打印一个#,覆盖刷新一次进度条。
for(i=0;i<persent_counts/10;i++)
printf("#");
printf("]");
//打印进度条整体样式,/r表示使光标定位到本行首,覆盖之前打印的进度条,即刷新
printf("%d%%...%c\r",persent_counts,label[(index==3?index=0:index++)]);
fflush(stdout); //刷新标准输出缓冲区,及时打印到终端
//usleep的单位微秒,1秒=10000毫秒,1毫秒=1000微秒,设置成睡眠0.5秒
usleep(1000*500);
//
if(100==persent_counts)
{
printf("\nCopy complete!\n");
break;
}
}
/* //3.关闭源文件、目标文件 */
if(close(fd_src)==0 && close(fd_des)==0)
{
printf("Close files successfully!\n");
}else
{
perror("Close files failed!!!\n");
return -3;
}
free(buf); //释放buffer
free(src_file); //释放堆空间
free(des_file);
return 0;
}