今天工作的时候遇到一个问题,需要将一系列文件中的某个字符串替换成另一字符串,手动替换太麻烦了,于是就想写个小程序来完成这一任务。
(具体工作是:我在做卫星网络的仿真,要将STK生成的轨道文件(200多个)导入到OPNET中,但要将每个轨道文件中的"EphemerisTimePosVel"替换为“EphemerisEcfTimePosVel”)
我用MFC做了一个简单的界面:
程序的实现涉及到以下几方面:
1. 某个目录下文件的查找;
2. 文件内容的读取、替换与写入;
3. “选择文件夹”对话框的实现。
下面分别介绍。
1. 某个目录下文件的查找
文件的查找使用CFileFind类,实现代码如下:
void CmodifyFilesDlg::OnBnClickedButtonFind()
{
CString strCurrDir; // 选择的文件夹路径
CString findStr; // 要查找的字符串
CString replaceStr; // 要替换的字符串
CString extStr; // 要修改的文件的后缀名
m_dirStr.GetWindowText(strCurrDir);
m_strFind.GetWindowText(findStr);
m_strReplace.GetWindowText(replaceStr);
m_fileExt.GetWindowTextW(extStr);
m_fileList.ResetContent();
CFileFind finder;
BOOL bWorking = finder.FindFile(strCurrDir + _T("\\*.")+extStr); // 查找该路径下指定后缀的文件,若找到,返回值为true
while (bWorking)
{
bWorking = finder.FindNextFile(); // 继续查找下一个,若找到,返回值为true
CString tempFileName = finder.GetFilePath(); // 获得上一个查找到的文件的完整路径
if (finder.IsDots()) continue;
if (finder.IsDirectory()) continue;
else
{
m_fileList.AddString(tempFileName);
2. 文件内容的读取、替换与写入
文件内容的读取和写入使用CFile类。
使用CFile的Read函数将文件内容读取到char数组中:
CFile file(tempFileName, CFile::modeReadWrite); // 以读写模式打开
DWORD len = file.GetLength();
char *buf = new char[len + 1];
buf[len] = 0;
file.Read(buf, len);
为了使用CString的查找替换功能,要进行char*和CString之间的转换。首先是从char*到CString,可以直接利用CString的构造函数:
CString fileContent(buf);
然后利用CString的Replace函数进行字符串的替换,这里一次调用实现全部替换:
fileContent.Replace(findStr, replaceStr);
接着要进行文件的写入。起初,我天真地调用了下面这句:
//file.Write(fileContent, fileContent.GetLength());
但是,输出得到的文件内容要么不完整,要么乱码。找了些资料,发现问题在于:CString使用的是Unicode字符,但CFile的Write函数是以字节形式写入的,所以,在写入前要进行CString到char*的转换,这里用到了WideCharToMultiByte函数:
int nLength = fileContent.GetLength();
int nBytes = WideCharToMultiByte(CP_ACP, 0, fileContent, nLength, NULL, 0, NULL, NULL); // 得到需要的字节数
char* newbuf = new char[nBytes + 1];
WideCharToMultiByte(CP_OEMCP, 0, fileContent, nLength, newbuf, nBytes, NULL, NULL); // 字符的转换
newbuf[nBytes] = 0;
接下来,就进行文件的写入。这里,要实现文件内容的覆盖,就是说,先要将原文件的内容清空,这里使用SetLength函数:
file.SeekToBegin(); // 指向文件开头
file.SetLength(0); // 清空文件内容
file.Write(newbuf, nBytes);
//file.Write(fileContent, fileContent.GetLength());
delete(newbuf);
delete(buf);
file.Close();
}
}
MessageBox(_T("替换完毕"));
finder.Close();
}
3. “选择文件夹”对话框的实现
使用CFolderPickerDialog类:
void CmodifyFilesDlg::OnBnClickedButtonOpen()
{
CFolderPickerDialog dlg;
if (dlg.DoModal() == IDOK)
{
m_dirStr.SetWindowText(dlg.GetFolderPath()); // 获得路径
}
}
程序实现了,可以方便地批量查找替换文件内容了!