C代码实现拷贝文件的进度编译成库后QT调用回调函数获取进度后显示在界面的进度条
曾经做过一个嵌入式项目,用c编写了一个获取拷贝文件进度的库,这个库要在QT中使用,Qt获取拷贝的进度,然后在界面显示出来:c库实现获取拷贝的进度,留有回调函数的接口,然后再Qt中注册这个回调函数,C库每次获取拷贝进度后会将进度值通过回调返回给Qt
整个代码的核心就是在.h文件中定义回调函数,定义设置回调函数的一个库函数
然后在.c文件中实现设置回调的库函数,以便给QT使用,QT会使用设置回调的库函数将代表自身的this指针传递,这样就可以使用了
c库
在.h文件中定义回调函数
#ifndef __FILE_CTRL_H_
#define __FILE_CTRL_H_
#include "db_ctrl.h"
#ifdef __cplusplus
extern "C" {
#endif
/** 定义回调函数 */
typedef void (*progress_callback)(int progress, void *userPtr);
* @description: 设置回调函数
* @param {*} cb 回调函数指针
* @return {*}
int file_setCallback(progress_callback cb, void *userPtr);
* @description:把文件拷贝到目录
* @param {char} *file_name 源文件名
* @param {char} *dir_name 目的文件目录
* @return {*}
int file_copyFileToDir(char *file_name, char *dir_name);
* @description: 删除文件
* @param {*}char *file_name 被删除源文件
* @return {*}
int file_deleteFile(char *file_name);
* @description: 视频文件压缩
* @param {*}
* @return {*}
int file_compressVideoFile(ST_VIDEO_DB_DATA stVideoDbData, char *videoFileName);
* @description: 视频文件解压缩
* @param {*}
* @return {*}
int file_UncompressVideoFile(ST_VIDEO_DB_DATA *stVideoDbData, char *videoFileName, char *zipName);
* @description: 压缩日志文件夹
* @param {char} *LogFileName
* @return {*}
int file_compressLogFile(char *LogFileName);
* @description:获取带后缀文件名的两个函数
* @param {char} *filePath
* @return {*}
char *GetFileName1(char *filePath);
#ifdef __cplusplus
#endif
#endif
在.c文件中实现设置回调函数
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "file_ctrl.h"
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "string_parse.h"
/** 全局回调函数 */
static progress_callback g_cb;
static void *g_userPtr;
void *get_frate_fmc(void *args);
typedef struct {
char file_name[128];
char dir_name[128];
progress_callback cb;
void *userPtr;
int run_flag;
}ST_GET_RATE;
/** 设置回调函数 */
int file_setCallback(progress_callback cb, void *userPtr)
g_cb = cb;
g_userPtr = userPtr;
return 0;
/** 获取速率线程状态 */
void *get_frate_fmc(void *args)
ST_GET_RATE *pstGetRate = (ST_GET_RATE*)args;
int nSrcFileSize = 0;
int nDestFileSize = 0, nDestTempSize = 0;
int fRate = 0;
int test = 0;
/** 获得原文件的大小 */
nSrcFileSize = getFileSize(pstGetRate->file_name);
while(1){
sleep(1);
/** 如果run_flag为0,退出线程 */
if(pstGetRate->run_flag == 0){
pstGetRate->cb(100, pstGetRate->userPtr);
break;
// 如果dir_name为0,采用定时发送进度信息
if(strlen(pstGetRate->dir_name) == 0){
fRate++;
if(pstGetRate->cb) pstGetRate->cb(fRate, pstGetRate->userPtr); //进度通过回调发送出去
continue;
/** 获得目的文件的大小 */
nDestTempSize = getFileSize(pstGetRate->dir_name);
if(nDestTempSize == 0)
nDestFileSize += 6000;
nDestFileSize = nDestTempSize;
/*** 计算复制的进度 */
if(nSrcFileSize) {
fRate = nDestFileSize * 100 / nSrcFileSize;
if(pstGetRate->cb) pstGetRate->cb(fRate, pstGetRate->userPtr); //进度通过回调发送出去
/** 复制完成之后,退出循环 */
if (nSrcFileSize == nDestFileSize)
if(pstGetRate->cb) pstGetRate->cb(100, pstGetRate->userPtr);
break;
/** 拷贝一个文件到一个目录 */
int file_copyFileToDir(char *file_name,char *dir_name)
int ret;
pthread_t pth;
/** shell执行的命令 ,在创建文件的时候使用*/
char szExcueCommand[150] = {0};
ST_GET_RATE stGetRate;
strcpy(stGetRate.file_name, file_name);
strcpy(stGetRate.dir_name, dir_name);
stGetRate.cb = g_cb;
stGetRate.userPtr = g_userPtr;
stGetRate.run_flag = 1;
// 创建线程
ret = pthread_create(&pth, NULL, get_frate_fmc, (void*)&stGetRate);
if(ret < 0){
printf("Create pthread for \'\' is Failed - %d!\n", ret);
return -1;
// 执行拷贝
sprintf(szExcueCommand,"cp %s %s",file_name,dir_name);
system(szExcueCommand);
// 关闭线程,等待线程结束
stGetRate.run_flag = 0;
pthread_join(pth, 0);
return 0;
* @description: 删除文件
* @param {*}char *file_name 被删除源文件
* @return {*}
int file_deleteFile(char *file_name)
char szExcueCommand[150] = {0};
if(!file_name) return -1;
sprintf(szExcueCommand,"rm -r %s",file_name);
system(szExcueCommand);
return 0;
* @description: 获取文件大小
* @param {*}
* @return {*}
int getFileSize(char *file_name)
struct stat buf = {0};
stat(file_name, &buf);
return buf.st_size / 1024;
* @description: 压缩数据库视频文件,将视频文件和描述.txt文件一同压缩
* @param {ST_VIDEO_DB_DATA} stVideoDbData 视频数据库文件
* @param {char} *videoFileName 被压缩的视频源文件地址
* @param {char} *zipName 压缩后的ZIP包文件地址
* @return {*}
int file_compressVideoFile(ST_VIDEO_DB_DATA stVideoDbData, char *videoFileName)
FILE *fp = NULL;
struct tm timeinfo;
char ch_event[10240] = "";
char ch_temp[64] = "";
char ZipCmd[128] = "";
char Zip_Name[64] = "";
char txtName[64] = "";
char txt_file[4096] = "";
char rm_txtfile[64] = "";
char rm_zipfile[64]="";
char ch_tmp[32] = "";
int i;
time_t startTime, endTime, eventTime[512];
int ret;
pthread_t pth;
ST_GET_RATE stGetRate;
// 生产txt说明文件
GetFileName3(stVideoDbData.file_path, Zip_Name); //去除后缀名
sprintf(txtName, "%s.txt", Zip_Name);
fp = fopen(txtName, "at+");
if(fp == NULL){
return;
timeinfo.tm_year = stVideoDbData.stStartTime.year - 1900;
timeinfo.tm_mon = stVideoDbData.stStartTime.month - 1;
timeinfo.tm_mday = stVideoDbData.stStartTime.date;
timeinfo.tm_hour = stVideoDbData.stStartTime.hour;
timeinfo.tm_min = stVideoDbData.stStartTime.minute;
timeinfo.tm_sec = stVideoDbData.stStartTime.second;
startTime = mktime(&timeinfo);
timeinfo.tm_year = stVideoDbData.stEndTime.year - 1900;
timeinfo.tm_mon = stVideoDbData.stEndTime.month - 1;
timeinfo.tm_mday = stVideoDbData.stEndTime.date;
timeinfo.tm_hour = stVideoDbData.stEndTime.hour;
timeinfo.tm_min = stVideoDbData.stEndTime.minute;
timeinfo.tm_sec = stVideoDbData.stEndTime.second;
endTime = mktime(&timeinfo);
for(i = 0; i < stVideoDbData.event_cnt; i++){
timeinfo.tm_year = stVideoDbData.stEventTime[i].year - 1900;
timeinfo.tm_mon = stVideoDbData.stEventTime[i].month - 1;
timeinfo.tm_mday = stVideoDbData.stEventTime[i].date;
timeinfo.tm_hour = stVideoDbData.stEventTime[i].hour;
timeinfo.tm_min = stVideoDbData.stEventTime[i].minute;
timeinfo.tm_sec = stVideoDbData.stEventTime[i].second;
eventTime[i] = mktime(&timeinfo);
memset(ch_temp, 0, sizeof(ch_temp));
sprintf(ch_temp, "%d", eventTime[i]);
strcat(ch_temp, "#");
strcat(ch_event, ch_temp);
flock(fp, LOCK_EX);
sprintf(txt_file, "%d\n%s\n%d\n%s\n%s\n%d\n%d\n%s\n%d,", stVideoDbData.chn_id,stVideoDbData.descriptor,stVideoDbData.event_cnt,\
stVideoDbData.file_name,stVideoDbData.file_path,stVideoDbData.record_time_len,endTime,ch_event,startTime);
fputs(txt_file, fp);
fflush(fp);
flock(fp, LOCK_UN);
// 关闭文件
fclose(fp);
fp = NULL;
strncat(Zip_Name, ".zip", 5);//将压缩文件后缀名添加进去
// 创建线程
strcpy(stGetRate.file_name, videoFileName);
strcpy(stGetRate.dir_name, Zip_Name);
stGetRate.cb = g_cb;
stGetRate.userPtr = g_userPtr;
stGetRate.run_flag = 1;
ret = pthread_create(&pth, NULL, get_frate_fmc, (void*)&stGetRate);
if(ret < 0){
printf("Create pthread for \'\' is Failed - %d!\n", ret);
return -1;
// 删除原压缩文件
sprintf(rm_zipfile, "rm -rf %s", Zip_Name);
system(rm_zipfile);
// 执行压缩指令
sprintf(ZipCmd,"zip -1qj %s %s %s",Zip_Name,stVideoDbData.file_path,txtName);
system(ZipCmd);
// 删除已经压缩的txt说明文件
sprintf(rm_txtfile,"rm -r %s",txtName);
system(rm_txtfile);
// 结束线程
stGetRate.run_flag = 0;
pthread_join(pth, 0);
* @description: 压缩日志文件夹
* @param {char} *LogFileName
* @return {*}
int file_compressLogFile(char *LogFileName)
int ret;
pthread_t pth;
ST_GET_RATE stGetRate;
char Zip_Name[64] = "";
char ZipCmd[128] = "";
printf("LogFileName=%s\n",LogFileName);
strcpy(Zip_Name,LogFileName);
strncat(Zip_Name,".zip",5);
printf("Zip_Name:%s\n",Zip_Name);
// 创建线程
strcpy(stGetRate.file_name, LogFileName);
strcpy(stGetRate.dir_name, Zip_Name);
stGetRate.cb = g_cb;
stGetRate.userPtr = g_userPtr;
stGetRate.run_flag = 1;
printf("stGetRate.file_name:%s\n",stGetRate.file_name);
printf("stGetRate.dir_name:%s\n",stGetRate.dir_name);
ret = pthread_create(&pth, NULL, get_frate_fmc, (void*)&stGetRate);
if(ret < 0){
printf("Create pthread for \'\' is Failed - %d!\n", ret);
return -1;
sprintf(ZipCmd,"zip -1rqj %s %s",Zip_Name,LogFileName);
printf("ZipCmd:%s",ZipCmd);
system(ZipCmd);
// 结束线程
stGetRate.run_flag = 0;
pthread_join(pth, 0);
/** 从文件中读取一行内容 */
#define FILEBUFFER_LENGTH 5000
#define EMPTY_STR ""
int file_get_file_line(char *result, char *fileName, int lineNumber)
FILE *filePointer;
int i=0;
char buffer[FILEBUFFER_LENGTH];
char *temp;
memset(buffer,'\0',FILEBUFFER_LENGTH*sizeof(char));
strcpy(buffer,EMPTY_STR);
if((fileName==NULL)||(result==NULL))
return 0;
strcpy(result, "");
if(!(filePointer=fopen(fileName,"rb")))
{return 0;}
while((!feof(filePointer))&&(i<lineNumber))
if(!fgets(buffer,FILEBUFFER_LENGTH,filePointer))
return 0;
i++;//差点又忘记加这一句了
/* printf("\n%d\n",sizeof(*result));
if(strlen(buffer)>sizeof(*result))//不能够这么写,虽然fgets读取一行后会在末尾加上'\0',但是sizeof(result)得到的结果却是result本身类型的大小,所以不能够这么算。当静态数组传入函数时,在函数内部只能知道它是一个指针
return 0;
if(0!=fclose(filePointer))
return 0;
if(0!=strcmp(buffer,EMPTY_STR))
while(NULL!=(temp=strstr(buffer,"\n")))
*temp='\0';
while(NULL!=(temp=strstr(buffer,"\r")))
*temp='\0';
strcpy(result,buffer);
}else
strcpy(result,EMPTY_STR);
return 0;
return 1;
* @description: 视频文件解压缩
* @param {ST_VIDEO_DB_DATA} *stVideoDbData
* @param {char} *videoFileName
* @param {char} *zipName
* @return {*}
int file_UncompressVideoFile(ST_VIDEO_DB_DATA *stVideoDbData, char *videoFileName, char *zipName)
ST_VIDEO_DB_DATA *pstVideoDbData = NULL;
char ch = '.';
FILE *fp = NULL;
char extension[64] = "";
char unzip_cmd[64] = "";
char line[1024] = "";
char line_1[64] = "";
char txt_filename[64] = "";
char video_filename[64] = "";
char txt_name[64] = "";
char path_name[64] = "";
int line_cnt;
ST_VIDEO_Search stVideoSearch;
int nSearchCnt;
int i, ret;
char *saveptr = NULL;
struct tm *timeinfo = NULL;
int nTime;
char *p = NULL;
char qq[64] = "";
char rm_txtfile[64]="";
ST_GET_RATE stGetRate;
pthread_t pth;
char *q = strrchr(zipName, ch); //strrchr从后往前获取,一直到'.'
if(q==NULL)
return -1;
printf("%s\n",q);
struct tm tm_time;
if(!strcmp(q,".zip"))
// 获取txt名称和video名称
GetFileName2(zipName,txt_name);
sprintf(txt_filename, "/msata/dr_video/%s.txt",txt_name);
strcpy(stGetRate.file_name, zipName);
strcpy(stGetRate.dir_name, "");
stGetRate.cb = g_cb;
stGetRate.userPtr = g_userPtr;
stGetRate.run_flag = 1;
// 创建线程
ret = pthread_create(&pth, NULL, get_frate_fmc, (void*)&stGetRate);
if(ret < 0){
printf("Create pthread for \'\' is Failed - %d!\n", ret);
return -1;
sprintf(unzip_cmd,"unzip -o -d /msata/dr_video/ %s", zipName);
system(unzip_cmd);
// 退出线程
stGetRate.run_flag = 0;
pthread_join(pth, 0);
if((access(txt_filename,F_OK))!=-1)
file_get_file_line(line, txt_filename, 1);
stVideoDbData->chn_id=atoi(line);
file_get_file_line(line, txt_filename, 2);
strcpy(stVideoDbData->descriptor,line);
file_get_file_line(line, txt_filename, 3);
stVideoDbData->event_cnt=atoi(line);
file_get_file_line(line, txt_filename, 4);
strcpy(stVideoDbData->file_name,line);
file_get_file_line(line, txt_filename, 5);
strcpy(stVideoDbData->file_path,line);
GetFileName2(stVideoDbData->file_path,extension);
q = strrchr(stVideoDbData->file_path, ch); //strrchr从后往前获取,一直到'.'
strcpy(qq,q);
printf("%s %s\n",extension, qq);
sprintf(stVideoDbData->file_path,"/msata/dr_video/%s%s",extension,qq);
file_get_file_line(line, txt_filename, 6);
stVideoDbData->record_time_len=atoi(line);
file_get_file_line(line, txt_filename, 7);
nTime = atoi(line);
timeinfo = gmtime((time_t*)&nTime);
stVideoDbData->stEndTime.year=timeinfo->tm_year+1900;
stVideoDbData->stEndTime.month=timeinfo->tm_mon + 1;
stVideoDbData->stEndTime.date=timeinfo->tm_mday;
stVideoDbData->stEndTime.hour=timeinfo->tm_hour;
stVideoDbData->stEndTime.minute=timeinfo->tm_min;
stVideoDbData->stEndTime.second=timeinfo->tm_sec;
file_get_file_line(line, txt_filename, 8);
if(stVideoDbData->event_cnt != utils_string_parse_delimiter_count(line, '#'))
return 0;
for(i = 0; i < stVideoDbData->event_cnt; i++){
if(i == 0){
p = utils_string_parse_strtok_r(line, '#', &saveptr);
} else {
p = utils_string_parse_strtok_r(NULL, '#', &saveptr);
if(p == NULL){
return 0;
nTime = atoi(p);
timeinfo = gmtime((time_t*)&nTime);
stVideoDbData->stEventTime[i].year = timeinfo->tm_year + 1900;
stVideoDbData->stEventTime[i].month = timeinfo->tm_mon + 1;
stVideoDbData->stEventTime[i].date = timeinfo->tm_mday;
stVideoDbData->stEventTime[i].hour = timeinfo->tm_hour;
stVideoDbData->stEventTime[i].minute = timeinfo->tm_min;
stVideoDbData->stEventTime[i].second = timeinfo->tm_sec;
file_get_file_line(line, txt_filename, 9);
nTime = atoi(line);
timeinfo = gmtime((time_t*)&nTime);
stVideoDbData->stStartTime.year=timeinfo->tm_year+1900;
stVideoDbData->stStartTime.month=timeinfo->tm_mon + 1;
stVideoDbData->stStartTime.date=timeinfo->tm_mday;
stVideoDbData->stStartTime.hour=timeinfo->tm_hour;
stVideoDbData->stStartTime.minute=timeinfo->tm_min;
stVideoDbData->stStartTime.second=timeinfo->tm_sec;
file_get_file_line(line, txt_filename, 10);
stVideoDbData->audio_resample=atoi(line);
file_get_file_line(line, txt_filename, 11);
strcpy(stVideoDbData->file_path_sec,line);
db_searchVideoDbData(stVideoSearch, &nSearchCnt, &pstVideoDbData);
for(i = 0; i < nSearchCnt; i++)
if(!strcmp(pstVideoDbData[i].file_name,stVideoDbData->file_name)){
db_releaseVideoDbData();
sprintf(rm_txtfile,"rm -r %s",txt_filename);
system(rm_txtfile);
return 1;
db_addVideoDbData(*stVideoDbData);
db_releaseVideoDbData();
sprintf(rm_txtfile,"rm -r %s",txt_filename);
system(rm_txtfile);
return 0;
else return -1;
return -1;
* @description:获取文件带.后缀名的两个函数
* @param {constchar} *file_name 文件的名字
* @param {char} *extension 得到的文件的后缀
* @return
void get_extension(const char *file_name,char *extension)
int i = 0, length;
length = strlen(file_name);
while(file_name[i])
if(file_name[i] == '.')
break;
if(i<length)
strcpy(extension, file_name+i+1);
strcpy(extension, "\0");
void get_extension_2(const char *file_name,char *extension)
char ch = '.'; // .代表文件后缀的起始
char *q = strrchr(file_name, ch); // 文件后缀名不能去掉.
memcpy(extension,q,sizeof(q));
* @description:获取带后缀的文件名
* @param {char} *filePath
* @return {*}
char *GetFileName1(char *filePath)
// int len = strlen(filePath);
char ch = '//'; // 其中一个反斜杠是转义字符
char *q = strrchr(filePath, ch) + 1; // 注意这里要+1, 否则输出是:\filename.exe
return q;
* @description: 获取不带后缀不带路径的文件名
* @param {char} *filePath
* @param {char} *extension
* @return {*}
void GetFileName2(char *filePath,char *extension)
int i = 0;
int start, end;
if(filePath == NULL || extension == NULL)
return;
while(filePath[i] != '\0'){
if(filePath[i] == '/')
start = i + 1;
if(filePath[i] == '.'){
end = i;
break;
strncpy(extension, filePath+start, end-start);
* @description:获取不带后缀带路径的文件名
* @param {char} *filePath
* @return {*}
void GetFileName3(char *filePath,char *extension)
int i = 0;
if(filePath == NULL || extension == NULL)
return;
while(filePath[i] != '\0'){
if(filePath[i] == '.')
break;
strncpy(extension, filePath, i);
**为了清楚,单独写一个子函数实现判断两个字符串匹配
char *match( char *str, char *want)
while( *want != NULL)
if( *str++ != *want++ )
return NULL;
return str;
**删除子串函数
int del_substr( char *str, char *substr )
char *next;
char *find = str;
**保证被操作字符串不为空
while( *find != NULL)
next = match( find, substr );
if( next != NULL)
break;
find++;
**到达源字符串文件尾的时候,说明没有子串
if( *find == NULL)
return -1;
**被删除子串之后的字符复制操作
while( *find++ = *next++ );
return 0;
}
Qt里面使用回调函数在界面显示拷贝文件的进度
static void progress(int progress, void *userPtr)
int calc_progress;
QString progress_int;
file_select *file_Select = (file_select*)userPtr; //将传递过来的指针转换
calc_progress=(file_Select->progress_count*100 + progress ) / file_Select->All_selectcont;
progress_int=QString::number(calc_progress)+"%";
file_Select->ui->label_4->setText(progress_int); //设置Qt界面中的label
usleep(2);
QPalette palette;
palette.setColor(QPalette::Text,Qt::white);
file_Select->ui->progressBar->setPalette(palette);
file_Select->ui->progressBar->setStyleSheet("QProgressBar{background:rgb(136,136,136);} QProgressBar::chunk{background:rgb(0,0,136)}");
file_Select->ui->progressBar->setValue(calc_progress);
usleep(100);
//file_Select->ui->progressBar->setStyleSheet("");
file_Select->ui->progressBar->setValue(calc_progress);
file_select::file_select(QWidget *parent) :
QWidget(parent),
ui(new Ui::file_select)
ui->setupUi(this);
ui->tableWidget->viewport()->installEventFilter(this); //注册事件过滤器
ui->tableWidget->verticalScrollBar()->installEventFilter(this);
ui->tableWidget->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
ui->tableWidget->horizontalHeader()->setStretchLastSection(false);
ui->tableWidget->setColumnWidth(0, 60);
ui->tableWidget->setColumnWidth(1, 60);
ui->tableWidget->setColumnWidth(2,300);
ui->tableWidget->setColumnWidth(3,200);
ui->tableWidget->setColumnWidth(4,230);
ui->tableWidget->setRowHeight(0,100);
ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows); //
ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); //
file_setCallback(progress,this); //使用c库中的函数,设置回调函数,这是一个QT的界面,所以可以用this指针代替
this->len=0;
this->dr_video=1;
this->All_selectFlag = 0;
this->udiskFlag=0;
this->query_startVideo=0;
this->query_endVideo=0;