用C语言、系统IO实现文件复制(带进度条)

用C语言、系统IO实现文件复制(带进度条)

用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;
}