1. 程式人生 > 實用技巧 >用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;
}