我们应该都用过迅雷这种下载工具吧,迅雷下载工具中运用了多线程下载。多线程文件拷贝是实现多线程下载的基础,下面给出了多线程文件拷贝的实现代码:
//copyfile.cc
#include <iostream>
#include <cstring>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
using namespace std;
/************************************
*使用指定线程实现从文件的拷贝
*创建时间:2011.07.28
*修改时间:2011.07.29
*作者:hahaya
***********************************/
//最大使用的线程数
const int MAX_THREADS = 5;
typedef struct TAG_INFO
{
char *fromfile; //源地址
char *tofile; //目的地址
int num; //启动的第i-1个进程
}info;
//st_size的类型为__off_t
int get_size(const char *filename)
{
struct stat st;
memset(&st, 0, sizeof(st));
stat(filename, &st);
return st.st_size;
}
void* threadDL(void *param)
{
info info1 = *((info*)param);
FILE *fin = fopen(info1.fromfile, "r+");
FILE *fout = fopen(info1.tofile, "w+");
int size = get_size(info1.fromfile);
//将文件指针分别设置在每个线程要读和写的位置
fseek(fin, size*(info1.num)/MAX_THREADS, SEEK_SET);
fseek(fout, size*(info1.num)/MAX_THREADS, SEEK_SET);
char buff[1024] = {'\0'};
int len = 0;
int total = 0;
while((len = fread(buff, 1, sizeof(buff), fin)) > 0)
{
fwrite(buff, 1, len, fout);
total += len;
//如果读入的数据大于文件总大小除线程总数则停止读入,因为每个线程要读或写的数据就等于文件总大小除线程总数
//可能会多写入一些数据,下一次写入时会覆盖多写入的数据,所以不用担心
if(total > size/MAX_THREADS)
{
break;
}
}
fclose(fin);
fclose(fout);
}
int main(int argc, char *argv[])
{
//先创建一个与文件1同样大小的文件
creat(argv[2], 0777);
truncate(argv[2], get_size(argv[1]));
pthread_t pid[MAX_THREADS];
info info1;
//启动指定线程数的线程
for(int i = 0; i < MAX_THREADS; i++)
{
memset(&info1, 0, sizeof(info1));
info1.fromfile = argv[1];
info1.tofile = argv[2];
info1.num = i;
pthread_create(&pid[i], NULL, threadDL, (void*)&info1);
}
//等待线程结束
for(int j = 0; j < MAX_THREADS; j++)
{
//pthread_join不能用在创建进程的for循环中,否则创建第一个进程后会等待第一个进程结束后创建第二个进程
pthread_join(pid[j], NULL);
}
cout << "file copy success......" << endl;
return 0;
}
程序运行截图:
复制后的文件是完整的,可以解压,如下图: