341上位机VC MFC实现多线程文件下载
实现多线程文件下载
功能展示
文件下载大家都有操作过,那么如何用代码实现文件的下载呢?我们当前例程就实现多线程的文件下载功能,效果如图。输入下载地址后,就可点击按钮进行文件的下载,下载的文件默认保存在C盘,并会在列表框中显示下载后的信息
要点提示
例程中下载文件时,首先是确定要下载的文件的大小,再根据文件的大小决定每个线程要下载文件的大小,每个线程下载完成文件的不同部分后,将每个线程下载的部分按顺序组成一个完整的文件,这样就实现了多线程下载文件功能;
实现功能
1.新建基于对话框的应用程序
2.添加下载函数所在头文件,按照例程界面添加编辑框控件IDC_EDIT1,按钮控件<下载>列表框控件IDC_LIST1,关联按钮的点击函数
void CGkbc8Dlg::OnDownload()
{
GetDlgItemText(IDC_EDIT1,m_sDownloadURL);
if (m_sDownloadURL.IsEmpty())
{
MessageBox("请输入下载路径");
return;
}
CInternetSession * pSession = new CInternetSession;
CHttpConnection * pFtpCon = pSession->GetHttpConnection("127.0.0.1");
CInternetFile * pFile = (CInternetFile*)pSession->OpenURL(m_sDownloadURL,1,INTERNET_FLAG_TRANSFER_BINARY|INTERNET_FLAG_RELOAD);
DWORD len = pFile->SeekToEnd();
//确定划分几个线程下载,每个线程应下载的文件大小
m_PerFileSize= len / m_ThreadCount;
m_EndFileSize = m_PerFileSize+ len % m_ThreadCount;
delete pFile;
delete pFtpCon;
delete pSession;
int pos = m_sDownloadURL.ReverseFind('/');
CString filename = m_sDownloadURL.Right(m_sDownloadURL.GetLength()-pos-1);
CListCtrl* pListCtrl = (CListCtrl*)GetDlgItem(IDC_LIST1);
pListCtrl->InsertItem(pListCtrl->GetItemCount(),"");
pListCtrl->SetItemText(pListCtrl->GetItemCount()-1,0,filename);
CString time = CTime::GetCurrentTime().Format("%H:%M:%S");
pListCtrl->SetItemText(pListCtrl->GetItemCount()-1,1,time);
pListCtrl->SetItemText(pListCtrl->GetItemCount()-1,2,"C:\\"+filename);
for (int i = 0; i<m_ThreadCount; i++)
{
int* temp = new int ;
*temp = i;
m_pEvent.ResetEvent();
CreateThread(NULL,0,ThreadProc,temp,0,NULL);
}
for (int n = 0 ; n< m_ThreadCount; n++)
{
WaitForSingleObject(m_pEvent[n],INFINITE);
}
CFile file ("c:\\"+filename,CFile::modeCreate|CFile::modeWrite);
DWORD readsize;
for (int m = 0; m<m_ThreadCount; m++)
{
if (m < m_ThreadCount-1)
readsize = m_PerFileSize;
else
readsize = m_EndFileSize;
file.Write(m_pData[m],readsize);
}
delete[] m_pData;
m_pData = new void*[m_ThreadCount];
}
3.再在此函数前添加函数所调用的线程函数
DWORD WINAPI ThreadProc(LPVOID lpParameter )
{
int index = *(int*)lpParameter;
delete lpParameter;
CInternetSession * pSession = new CInternetSession;
CHttpConnection * pFtpCon = pSession->GetHttpConnection("127.0.0.1");
CGkbc8Dlg* pDlg = (CGkbc8Dlg*)AfxGetMainWnd();
CInternetFile* pFile = (CInternetFile*)pSession->OpenURL(pDlg->m_sDownloadURL);
DWORD readsize;
if (index < pDlg->m_ThreadCount-1)
readsize = pDlg->m_PerFileSize;
else
readsize = pDlg->m_EndFileSize;
pFile->Seek(index*pDlg->m_PerFileSize,FILE_BEGIN);
pDlg->m_pData[index] = LocalAlloc(LMEM_FIXED,readsize);
pFile->Read(pDlg->m_pData[index],readsize);
delete pFile;
delete pFtpCon;
delete pSession;
pDlg->m_pEvent[index].SetEvent();
return 0;
}
4.在程序退出时删除自定义的成员变量
void CGkbc8Dlg::OnDestroy()
{
CDialog::OnDestroy();
delete[] m_pData;
delete[] m_pEvent;
}
5.添加函数中使用的成员变量并在OnInitDialog()函数初始化
public:
UINT m_ThreadCount; //线程数量
DWORD m_PerFileSize; //每个线程下载的文件大小
DWORD m_EndFileSize; //最后一个线程下载的文件大小
void** m_pData; //每个线程序下载数据的缓冲区,在每个线程均下载完成后合成一个完整的文件
CEvent* m_pEvent; //事件对象,用于线程同步
CString m_sDownloadURL; //文件下载地址;
我们来演示下功能实现的整个过程
如果您认可,可联系功能定制! 如果您着急,充值会员可直接联系发您资料!
|