目录浏览及大文件在内存中的读写

来源:互联网 发布:淘宝怎么领取红包 编辑:程序博客网 时间:2024/06/08 04:42

         通过一个MFC实例,将硬盘中的某个文件拷贝到另一个目标目录中,并用进度条显示拷贝进度。通过该实例熟悉以下3个应用:一是目录浏览窗口的使用;二是大型文件(占上百兆)的读写及传输;三是精确显示操作进度百分比。

(1)创建一个对话框类CFileCopyDlg及对话框,在上面显示三个按钮,分别是源文件浏览(IDC_ADD)、目标目录浏览(IDC_DEST)、拷贝(IDC_COPY)。再放两个编辑框控件IDC_EDADD和IDC_EDDEST,分别显示源文件全路径和目标目录全路径。

class CFileCopyDlg : public CDialog
{

      ...................

      CString strname;        //源文件名
      CString fullname;       //目标目录名
      CString pathname;    //源文件全路径名
      HGLOBAL hGlobal;    //
      CFile* writefile;           //写文件句柄
      CFile* readfile;           //读文件句柄
      long readlen,poslen,filelen;    //
      LPVOID pvData;           //分配的内存操作指针

      CProgressCtrl m_fileproc; 

      ....................

};

(2)源文件浏览按钮的操作

void CFileCopyDlg::OnAdd()
{
        CFileDialog log(TRUE,"文件","*.*",OFN_HIDEREADONLY,"FILE(*.*)|*.*||",NULL);
        if(log.DoModal()==IDOK)
        {
               pathname=log.GetPathName();          //保存源文件全路径名
               strname=log.GetFileName();               //保存源文件名
               GetDlgItem(IDC_EDADD)->SetWindowText(pathname);
        }
}

(3)目标目录浏览按钮的操作

void CFileCopyDlg::OnPut()
{
        if(strname.IsEmpty())         //如果没有选取任何文件,返回
               return;
        BROWSEINFO bi;  
        char buffer[MAX_PATH];  
        ZeroMemory(buffer,MAX_PATH);  
        bi.hwndOwner=GetSafeHwnd();  
        bi.pidlRoot=NULL;  
        bi.pszDisplayName=buffer;   
        bi.lpszTitle="选择一个文件夹";   //浏览窗口标题
        bi.ulFlags=BIF_EDITBOX;  
        bi.lpfn=NULL;  
        bi.lParam=0;  
        bi.iImage=0;
        LPITEMIDLIST pList=NULL;    //浏览列表
        if((pList=SHBrowseForFolder(&bi))!=NULL)   //开始使用浏览窗口
        {  
               char path[MAX_PATH];
               ZeroMemory(path,MAX_PATH);
               SHGetPathFromIDList(pList,path);    //从列表中获得目录路径
               fullname=path;
               if(fullname.Right(1)!="\\")                   //如果路径名不带分隔符,需手工添加分隔符
                      fullname.Format("%s\\%s",path,strname);             //将路径名跟文件名组合
               else
                      fullname.Format("%s%s",path,strname);
               GetDlgItem(IDC_EDDEST)->SetWindowText(fullname);
        }
}

(4)拷贝按钮的操作

void CFileCopyDlg::OnCopy()
{

      if(pathname.IsEmpty())
             return;
      if(fullname.IsEmpty())        //如果以上两个按钮都没有操作,就返回
             return;
      readfile=new CFile(pathname,CFile::modeRead);           //读文件句柄赋值
      HANDLE hfile=::CreateFile(fullname,GENERIC_WRITE|GENERIC_WRITE,0,0,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,0);
      CloseHandle(hfile);         //这两句防止重复使用时出现共享违例错误
      writefile=new CFile(fullname,CFile::modeWrite);              //写文件句柄赋值


      filelen=readfile->GetLength();      //要读文件的文件长度,以字节为单位
      ldiv_t r;
      r=ldiv(filelen,100);
      long pos=r.quot;
      long ipos;
      ipos=pos;     //以100等分来分的话,每份要容纳pos个字节。也就是每传输pos个字节,进度条加1
      int i=0;            //进度条初始值和范围已设定
      hGlobal = GlobalAlloc(GMEM_MOVEABLE,512); 
      pvData = GlobalLock(hGlobal);     
      while(1)

      {
             ZeroMemory(pvData,512);
             readlen=readfile->ReadHuge(pvData,512);   //实际读长度
             poslen=readfile->GetPosition();    //相当于SEEK,移动文件指针,并返回已操作的长度
             if(poslen>ipos)      //如果已读长度大于等份累加长度
             {
                    ipos+=pos;      //变更等份累加长度
                    i++;                   //滑动条参数变更
             }
             m_fileproc.SetPos(i);
             m_fileproc.Invalidate();      //设置并更新滑动条
             writefile->WriteHuge(pvData,readlen);     //将指针内容写入文件
             if(poslen==filelen)                                     //传输完就退出循环
                   break;
      }
      AfxMessageBox("复制完成");
      m_fileproc.SetPos(0);
      GlobalUnlock(hGlobal);
      readfile->Close();
      writefile->Close();
}

需要注意的是:大文件的传递和烧录等过程都是一个划分成小单位操作的循环过程,都是以较小内存缓冲区进行操作的。