今天要写一个批量替换文件某一行内容的小程序,
开始的想法是直接在文件里操作(不生成新文件),于是写下如下代码(对单个文件操作)
- /*
- string m_strRepSrc;//被替换行中的标识字符串 vc98/include/
string m_strRepDes;//替换成的字符串 F:/Program Files/software/Microsoft Visual Studio 8/VC/include/ -
- 要求效果:
- "e:/program files/microsoft visual studio/vc98/include/basetsd.h"/
- 修改成==>
- "F:/Program Files/software/Microsoft Visual Studio 8/VC/include/basetsd.h"/
- 其中basetsd.h"/要求不变
- */
- bool CReplace::deal()
- {
- //打开文件
- CStdioFile hFile(m_strFilePath.c_str(), CFile::modeReadWrite|CFile::shareDenyWrite);
- //查找
- CString strTemp;
- CString newStr;
- LONG iIdx = 0;
- while (hFile.ReadString(strTemp))
- {
- iIdx = strTemp.Find(m_strRepSrc.c_str()); //如果行中含有标识字符串则进入替换
- if (iIdx != -1)
- {
- //获取不替换部分;
- newStr = strTemp.Right(strTemp.GetLength() - iIdx - 1 - m_strRepSrc.length()); //basetsd.h"/
- //替换成的字符串
- newStr = CString(_T("/"")) + CString(m_strRepDes.c_str()) + newStr + CString(_T("/n"));
- //写回文件
- hFile.Seek(-2-strTemp.GetLength(), CFile::current); //找到被替换字符串的起始位置
- hFile.WriteString(newStr.GetBuffer());
- newStr.ReleaseBuffer();
- }
- }
- hFile.Close();
- return true;
- }
结果程序一执行,不如人意,由于
"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读回前面的内容了,从而死循环
并且使目标文件增大了数倍(把前面的内容写进来了)....汗 ====>这里不明白为什么会把文件前面的内容写进来了...
结论:普通方法不能在一个文件里面直接替换文件内容,除非替换与被替换的字符串长度一样
长度一样的话,如下就可以实现
- lPos = hFile.GetPosition();
- hFile.Seek(-2-strTemp.GetLength(), CFile::current);
- hFile.WriteString(newStr.GetBuffer());
- newStr.ReleaseBuffer();
- hFile.Seek(lPos, CFile::begin);
最终,换方法,把文件内容读入内存,在内存中替换文件内容,然后写回文件...
实现如下- //将strBig中所有的strsrc替换成strdst
- void CReplace::string_replace(string & strBig, const string & strsrc, const string &strdst)
- {
- string::size_type pos=0;
- string::size_type srclen = strsrc.size();
- string::size_type dstlen = strdst.size();
- while((pos=strBig.find(strsrc, pos)) != string::npos)
- {
- strBig.replace(pos, srclen, strdst); //从索引pos开始的srclen个字符替换成后面的strdst
- pos += dstlen;
- }
- }
- bool CReplace::deal()
- {
- ifstream in(m_strFilePath.c_str());
- stringstream ss;
- ss << in.rdbuf();
- string s = ss.str();
- //size_type类型为unsigned型,与具体机器有关
- string::size_type iIdx=0;
- string::size_type iBegin, iEnd;
- iIdx = s.find(m_strRepSrc);
- if (iIdx != string::npos)
- {
- iBegin = s.rfind("/"", iIdx);
- iEnd = iIdx + m_strRepSrc.size();
- string sRep = s.substr(iBegin, iEnd-iBegin);
- //s.replace(sRep, m_strRepDes);
- string_replace(s, sRep, m_strRepDes);
- //写回
- ofstream out(m_strFilePath.c_str());
- out << s;
- //不需要out.close(),scope结束out析构会自动close()
- }
- in.close();
- return true;
- }