文件内容替换---郁闷的结果

来源:互联网 发布:产品淘宝上线流程 编辑:程序博客网 时间:2024/04/29 13:51

今天要写一个批量替换文件某一行内容的小程序,

开始的想法是直接在文件里操作(不生成新文件),于是写下如下代码(对单个文件操作)

  1. /* 
  2. string m_strRepSrc;//被替换行中的标识字符串 vc98/include/
    string m_strRepDes;//替换成的字符串 F:/Program Files/software/Microsoft Visual Studio 8/VC/include/
  3.             
  4.             要求效果:
  5.             "e:/program files/microsoft visual studio/vc98/include/basetsd.h"/
  6.             修改成==>
  7.             "F:/Program Files/software/Microsoft Visual Studio 8/VC/include/basetsd.h"/
  8.             其中basetsd.h"/要求不变
  9. */
  10. bool CReplace::deal()
  11. {
  12.     //打开文件 
  13.     CStdioFile hFile(m_strFilePath.c_str(), CFile::modeReadWrite|CFile::shareDenyWrite);
  14.     //查找 
  15.     CString strTemp;
  16.     CString newStr;
  17.     LONG iIdx = 0;
  18.     while (hFile.ReadString(strTemp))
  19.     {
  20.         iIdx = strTemp.Find(m_strRepSrc.c_str()); //如果行中含有标识字符串则进入替换
  21.         if (iIdx != -1)
  22.         {      
  23.             //获取不替换部分; 
  24.             newStr = strTemp.Right(strTemp.GetLength() - iIdx - 1 - m_strRepSrc.length()); //basetsd.h"/
  25.             //替换成的字符串 
  26.             newStr = CString(_T("/"")) + CString(m_strRepDes.c_str()) + newStr + CString(_T("/n"));
  27.             //写回文件 
  28.             
  29.             hFile.Seek(-2-strTemp.GetLength(), CFile::current); //找到被替换字符串的起始位置 
  30.             hFile.WriteString(newStr.GetBuffer());
  31.             newStr.ReleaseBuffer();
  32.         
  33.         }
  34.     }
  35.     hFile.Close();
  36.     
  37.     return true;
  38. }

结果程序一执行,不如人意,由于

"F:/Program Files/software/Microsoft Visual Studio 8/VC/include/basetsd.h"/ 长度要比

"e:/program files/microsoft visual studio/vc98/include/basetsd.h"/

导致文件中"e:/program files/microsoft visual studio/vc98/include/basetsd.h"/后面的内容被覆盖

之后由于

hFile.Seek(-2-strTemp.GetLength(), CFile::current); 

hFile.WriteString(newStr.GetBuffer());

的原因,导致hFile.ReadString读回前面的内容了,从而死循环

并且使目标文件增大了数倍(把前面的内容写进来了)....汗   ====>这里不明白为什么会把文件前面的内容写进来了...

 

结论:普通方法不能在一个文件里面直接替换文件内容,除非替换与被替换的字符串长度一样

长度一样的话,如下就可以实现

  1.             lPos = hFile.GetPosition();
  2.             hFile.Seek(-2-strTemp.GetLength(), CFile::current);
  3.             hFile.WriteString(newStr.GetBuffer());
  4.             newStr.ReleaseBuffer();
  5.             hFile.Seek(lPos, CFile::begin);

最终,换方法,把文件内容读入内存,在内存中替换文件内容,然后写回文件...

实现如下
  1. //将strBig中所有的strsrc替换成strdst
  2. void CReplace::string_replace(string & strBig, const string & strsrc, const string &strdst) 
  3. {
  4.         string::size_type pos=0;
  5.         string::size_type srclen = strsrc.size();
  6.         string::size_type dstlen = strdst.size();
  7.         while((pos=strBig.find(strsrc, pos)) != string::npos)
  8.         {
  9.             strBig.replace(pos, srclen, strdst); //从索引pos开始的srclen个字符替换成后面的strdst
  10.             pos += dstlen;
  11.         }
  12. }
  13. bool CReplace::deal()
  14. {
  15.     ifstream in(m_strFilePath.c_str());
  16.     stringstream ss;
  17.     ss << in.rdbuf();
  18.     string s = ss.str();
  19.     //size_type类型为unsigned型,与具体机器有关
  20.     string::size_type iIdx=0;
  21.     string::size_type iBegin, iEnd;
  22.     iIdx = s.find(m_strRepSrc);
  23.     if (iIdx != string::npos)
  24.     {
  25.         iBegin = s.rfind("/"", iIdx);
  26.         iEnd = iIdx + m_strRepSrc.size();
  27.         string sRep = s.substr(iBegin, iEnd-iBegin);
  28.         //s.replace(sRep, m_strRepDes);
  29.         string_replace(s, sRep, m_strRepDes);
  30.         //写回
  31.         ofstream out(m_strFilePath.c_str());
  32.         out << s;
  33.         //不需要out.close(),scope结束out析构会自动close()
  34.     }
  35.     in.close();
  36.     
  37.     return true;
  38. }
原创粉丝点击