今天要写一个批量替换文件某一行内容的小程序,
开始的想法是直接在文件里操作(不生成新文件),于是写下如下代码(对单个文件操作)
- /*
- 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;
- }
本文探讨了在不生成新文件的情况下直接修改文件内容的方法。通过对比不同实现方式,指出直接替换存在的问题,并提出了一种先将文件内容读入内存进行替换后再写回文件的有效解决方案。

被折叠的 条评论
为什么被折叠?



