一雨田的专栏

伟人将复杂的事情变简单,小人将简单的事情变复杂

用户操作
[即时聊天] [发私信] [加为好友]
一雨田ID:dylgsy
91676次访问,排名1090,好友2人,关注者13人。
一雨田
dylgsy的文章
原创 41 篇
翻译 1 篇
转载 6 篇
评论 292 篇
最近评论
heray818:我的邮箱是:heray818@126.com
heray818:你好 能否也传我一份 谢谢了啊
救援隊募集:アダルトエロ不倫
モテ度審査員:童貞セフレナンパ
temp:很好
文章分类
收藏
    相册
    好友Blog
    圈内朋友
    sankt的专栏
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 目录的打包和解包收藏

    新一篇: 设计模式简单代码之一 | 旧一篇:  Socket在阻塞模式下的信息收发和文件接收

    由于程序中需要把整个目录打包,所以自己写了打包和解包函数,我对此打包文件的布局设计如下: 

    20字节:表明目录结构的起点

     

                                       ……

    目录结构起点(前20个字节标明的):

     

    文件内容起点:

    文件FD结构

    文件FD结构

    文件内容

     

    文件内容

     

    目录FD结构

    目录FD结构

    目录FD结构

                                       ……

    20字节:表明目录结构的起点
     
                                       ……
    目录结构起点(前20个字节标明的):
     
    文件内容起点:
    文件FD结构
    文件FD结构
    文件内容
     
    文件内容
     
    目录FD结构
    目录FD结构
    目录FD结构
                                       ……
     上述的FD结构其实就是:
    typedef struct stFD
    {
     TCHAR szName[MAX_PATH]; // 文件或者目录名
     long nSize;  // 文件内容的大小,以字节表示,如果是目录大小为0
     FILETIME cTime;  // 创建时间
     FILETIME aTime; // 最后访问时间
     FILETIME mTime; // 最后改写时间
     DWORD attribute; // 表明文件的状态
    }FD;

    打包函数:

    void PackDir(LPCTSTR lpszDir, LPCTSTR lpszOutputFile)
    {// 给出一个目录,把这个目录打包
     // Param:
     //  lpszDir: 打包目录
     //     lpszOutputFile: 打包后的输出文件名
     
     const int nOffset = 20;
     CFileFind finder;
     CStringList strLst;
     FD fdTmp;
     CFileStatus fileStatus;
     CString strTmp;
     BOOL bWorking;
     CString strDir(_T(""));
     TCHAR *pszFileContent = NULL;
     CFile fileTmp;
     CString strFileDirTmp;
     TCHAR szCnt[nOffset];
     vector<FD> vDirFD;

     if(!finder.FindFile(lpszDir))
     {
      AfxMessageBox("目录不存在");
      return;
     }

     // 创建打包文件
     CFile PackFile;
     if(!PackFile.Open(lpszOutputFile, CFile::modeCreate|CFile::modeReadWrite, NULL))
     {
      AfxMessageBox("创建打包文件出错!");
      return;
     }
     
     // 先把文件开始的nOffset个字节占住,用于表示到目录结构所要偏移的字节数            
     PackFile.SeekToBegin();
     PackFile.Write(szCnt, nOffset); 

     strLst.AddTail(lpszDir);
     
     while(!strLst.IsEmpty())
     {
      strTmp = strLst.GetHead() + _T("\\*.*");
      bWorking = finder.FindFile(strTmp);
      if(bWorking)
      {
       while(bWorking)
       {
        bWorking = finder.FindNextFile();
        
        if(finder.IsDots())
         continue;
        
        finder.GetLastAccessTime(&fdTmp.aTime);
        finder.GetCreationTime(&fdTmp.cTime);
        finder.GetLastWriteTime(&fdTmp.mTime);
        
        strFileDirTmp = finder.GetFilePath();
        strFileDirTmp = strFileDirTmp.Right(strFileDirTmp.GetLength() - lstrlen(lpszDir));
        lstrcpy(fdTmp.szName, strFileDirTmp);
        
        fdTmp.nSize = finder.GetLength();
        fdTmp.attribute = GetFileAttributes(finder.GetFilePath());
        
        // 目录
        if(finder.IsDirectory())
        {
         // 保存下来,在后面再写进文件里
         vDirFD.push_back(fdTmp);

         strLst.AddTail(finder.GetFilePath());
         continue;
        }
        
        // 找到文件
        PackFile.SeekToEnd();

        // 将文件结构写进
        PackFile.Write(&fdTmp, sizeof(FD));
        // 将文件内容写进
        pszFileContent = new TCHAR[finder.GetLength()];

        if(!fileTmp.Open(finder.GetFilePath(), CFile::modeRead, NULL))
        {
         CString strErr;
         strErr.Format("写进打包文件时,打开文件%s出错!", finder.GetFilePath());
         AfxMessageBox(strErr);
         return;
        }
        fileTmp.Read(pszFileContent, finder.GetLength());
        PackFile.Write(pszFileContent, finder.GetLength());
        
        delete pszFileContent;
       }
      }
      
      strLst.RemoveHead();
     }
     
     // 在开始的nOffset个字节处写进目录结构偏移量
     DWORD dwCnt = PackFile.SeekToEnd();
     sprintf(szCnt, "%ld", dwCnt);
     PackFile.SeekToBegin();
     PackFile.Write(szCnt, nOffset);

     // 去到最后写进目录结构
     PackFile.SeekToEnd();
     for(int i = 0; i < vDirFD.size(); i++)
     {
      fdTmp = vDirFD[i];
      PackFile.Write(&fdTmp, sizeof(fdTmp));
     }

     PackFile.Close();
    }

     

     

     

     

     

    解包函数:

    void UnPackDir(LPCTSTR lpszInputFile, LPCTSTR lpszDir)
    {// 给出一个文件,把这个文件还原为目录
     // Param:
     //  lpszInputFile: 利用PackDir函数打包成的文件
     //  lpszDir: 还原到的目录路径
     
     const int nOffset = 20;
     TCHAR szCnt[nOffset];
     long nOff = 0;
     CString strDir;
     CString strFile;
     FD fdTmp;
     DWORD dwCurPos = 0;
     TCHAR *pszFileContent;

     CFile fileInput;
     if(!fileInput.Open(lpszInputFile, CFile::modeRead, NULL))
     {
      AfxMessageBox("打开输入文件出错!");
      return;
     }

     // 先建立目录结构
     memset(szCnt, 0, nOffset);
     fileInput.Read(szCnt, nOffset);
     nOff = atoi(szCnt);
     // 去到文件目录结构的起点
     fileInput.Seek( nOff, CFile::begin );
     while(!IsFileEnd(fileInput))
     {
      fileInput.Read(&fdTmp, sizeof(FD));
      strDir = lpszDir;
      strDir += fdTmp.szName;

      CreateDirectory(strDir, NULL);
        
      SetFileAttributes(strDir, fdTmp.attribute);
     }

     // 再把文件创建好
     dwCurPos = fileInput.Seek(nOffset, CFile::begin);
     CFile fileTmp;
     while(dwCurPos < nOff)
     {
      fileInput.Read(&fdTmp, sizeof(FD));
      strFile = lpszDir;
      strFile += fdTmp.szName;
      
      if(!fileTmp.Open(strFile, CFile::modeCreate | CFile::modeReadWrite, NULL))
      {
       CString strErr;
       strErr.Format("解包时创建文件%s出错!", strFile);
       AfxMessageBox(strErr);
       return;
      }
      // 把内容复制过去
      pszFileContent = new TCHAR[fdTmp.nSize];
      fileInput.Read(pszFileContent, fdTmp.nSize);
      fileTmp.SeekToBegin();
      fileTmp.Write(pszFileContent, fdTmp.nSize);
      delete pszFileContent;

      // 把文件的属性改变,先关闭再改
      fileTmp.Close();

      CFileStatus rStatus;
      CTime cTime(fdTmp.cTime);
      CTime aTime(fdTmp.aTime);
      CTime mTime(fdTmp.mTime);
      rStatus.m_atime = aTime;
      rStatus.m_ctime = cTime;
      rStatus.m_mtime = mTime;
      rStatus.m_attribute = (BYTE)fdTmp.attribute;
      rStatus.m_size = fdTmp.nSize;
      lstrcpy(rStatus.m_szFullName, strFile);

      CFile::SetStatus(strFile, rStatus);

      dwCurPos = fileInput.GetPosition();  
     }

     fileInput.Close();
    }

     


    还有一个判断是否到了文件末尾的函数:

    BOOL IsFileEnd(CFile &file)
    {
     DWORD dwFileLength = file.GetLength();
     DWORD dwFileCurPos = file.GetPosition();
     
     if(dwFileCurPos < dwFileLength)
     {
      return FALSE;
     }
     
     return TRUE;
    }

    发表于 @ 2006年06月29日 16:06:00|评论(loading...)|编辑

    新一篇: 设计模式简单代码之一 | 旧一篇:  Socket在阻塞模式下的信息收发和文件接收

    评论

    #一雨田 发表于2006-06-29 16:40:00  IP: 59.41.176.*
    这段代码只是一个TEST,所以没真正细想每一处函数返回时候的内存释放问题。真正使用的时候当然需要细心处理。
    #BlackHan 发表于2006-06-29 16:31:00  IP: 218.242.140.*
    注意代码:
    pszFileContent = new TCHAR[finder.GetLength()];

    if(!fileTmp.Open(finder.GetFilePath(), CFile::modeRead, NULL))
    {
    CString strErr;
    strErr.Format("写进打包文件时,打开文件%s出错!", finder.GetFilePath());
    AfxMessageBox(strErr);
    return;
    }

    呵呵 教科书式的内存泄露。
    上帝啊,为什么要惩罚C/C++程序员呢?

    无数的智能指针的实现,数据传输对象模式的封装,不透明指针(句柄模式)的应用在等待我们使用,为什么还要继续new.





    #gg 发表于2006-08-01 23:40:00  IP: 219.135.213.*
    ^_^
    #展松 发表于2006-08-10 21:46:00  IP: 219.137.95.*
    说得不错,受益不浅!!
    发表评论  


    登录
    Csdn Blog version 3.1a
    Copyright © 一雨田