在工作中遇到一个功能需求,就是读取一个资源文件,替换资源文件中某些字符,由于资源文件无法转化成字符串去替换,因为资源文件中有各种数据内容,那么怎么处理这个问题呢,我思考了几天想出一个较为完美的办法解决了这个问题,正文详细解说解决思路。

一、项目环境

VS2017下MFC程序

一、项目需求

读取一个资源文件(例如:VS2017项目文件中的xx.aps文件),替换资源文件中的oldName字符为newName字符

二、思路分析

资源文件xx.aps文件如果按常规的编码读入,转化为字符串然后替换字符串,再将转化后的数据写回去,这样是不可行的。因为资源文件并不完全是字符串类型的数据,里边包括了各种数据内容,如果强制全部转化为字符串必然出错。

分析MFC的可用函数
文件操作类:CFile
替换函数:CString::Replace()
我们用CFile以二进制读入xx.aps文件,并将二进制数据以十六进制字符形式转化为CString字符串,同时将oldName和newName都转化为十六进制字符,此时CString::Replace替换oldName十六进制字符为newName十六进制字符,然后把替换后的十六进制字符转化为二进制数据再用CFile写入回原文件,这样就巧妙得把任何数据转化为我们能够使用替换功能的CString字符串,从而达到我们的目的,这里我们约定全文使用:两位十六进制字符+空格,这样的格式进行十六进制转化,例如:6F B3 2C 66 2A

三、实现过程

1.字符串转十六进制字符

用于将oldName、newName字符串转化为十六进制字符串,代码如下:

CString toHex(CString str)
	CString sRet = "";
	//获取str的长度
	DWORD len = str.GetLength();
	//将获CString转化为char*
	char *tmp = new char[len + 1];
	memset(tmp, 0, len + 1);
	strcpy(tmp, str.GetBuffer(len));
	for (int i = 0; i < len; i++)
		//按两位十六进制字符格式组建sRet字符串
		sRet.AppendFormat("%02X ", (unsigned char)tmp[i]);
	delete[]tmp;
	return sRet;

2.替换功能

传入文件路径,替换oldName为newName,并返回替换数量,代码如下:

int replaceFile(CString strDir, CString oldName, CString newName)
	int iRet = 0;
	CFile file;
	// 以二进制读写模式打开strDir
	if (file.Open(strDir, CFile::modeReadWrite | CFile::typeBinary) == FALSE)
		return iRet;
	//获取读入数据的长度
	DWORD len = file.GetLength();
	if (len == 0)
		return iRet;
	//创建存储数据buf,并读入数据
	char *buf = new char[len + 1];
	memset(buf, 0, len + 1);
	file.Read(buf, len);
	//将读入的二进制char*转化为cstring十六进制文本
	CString cbuf;
	for (int i = 0; i < len; i++)
		cbuf.AppendFormat("%02X ", (unsigned char)buf[i]);
	//把oldName、newName都转化为约定的十六进制格式进行替换,iRet接收替换数量
	iRet = cbuf.Replace(toHex(oldName), toHex(newName));
	//计算替换后的文本对应char*数组长度,我们约定的(两位十六进制字符+空格)格式是3个长度
	DWORD wlen = (DWORD)(cbuf.GetLength() / 3) + 1;
	//定义用于写数据的char*,并将数组清0
	char* wbuf = new char[wlen];
	memset(wbuf, 0, wlen);
	//对每个char数组成员赋值替换后的十六进制数据
	for (int i = 0; i < wlen - 1; i++)
		//精髓在这里,巧妙的利用CString::Mid函数取出对应位置的十六进制字符,
		//通过strtol函数把字符串转化为整数,再赋值给写出的wbuf,
		//这样完成十六进制字符转化成char*写出数据
		wbuf[i] = strtol(cbuf.Mid(i * 3, 2), 0, 16);
	//指向文件开头
	file.SeekToBegin();
	//清空文件内容
	file.SetLength(0);
	//写入数据
	file.Write(wbuf, wlen);
	//别忘了删除new出来的对象
	delete[] wbuf;
	delete[] buf;
	file.Close();
	return iRet;

实现本需求的关键

1. 深刻理解char型数组操作
2. 理清不可控制的二进制数据与可操作的CString字符的相互转化过程
3. 明白数据资源文件的读写操作

实例010——使用Windows API创建程序窗口 实例011——使用AppWizard创建基于文档视图结构MFC应用程序框架 实例012——使用AppWizard建立对话框应用程序框架 实例013——实现查找、替换字符串 实例014——根据指定字符分割字符串 实例015——格式化字符串 实例016——CString字符串的类型转换 实例017——获取当前的日期、时间并格式化输出 实例018——计算某日为星期几 实例019——计算两个时间点的时间间隔 实例020——使用CStringArray类创建和使用字符串数组 实例021——使用CPtrList类创建和使用链表 using namespace std; bool copy_binary_file(const char * szDestFile, const char * szOrigFile) bool bRet = true; std::ofstream fout(szDestFile, st 379 如何捕获AR和Shift+Alt组合键? 380 如何捕获Ctrl和Ctrl+Shift组合键? 381 如何捕获Ctrl、Ctrl+Alt和Ctrl+Alt+Shifl组合键? 第20章 声音和视频 382 如何调节系统音量? 383 如何设置背景音乐? 384 如何播放AVI动画文件? 385 如何播放VCD视频文件? 386 如何播放WAV简单声音文件? 387 如何播放系统默认声音文件? 388 如何使用MCI播放WAV声音文件? 389 如何使用MCI播放MIDI声音文件? 第21章 图形和图像 390 如何通过读取位图资源显示位图? 391 如何通过读取位图文件显示位图? 392 如何通过装入位图文件显示位图? 393 如何缩放显示位图? 394 如何截取当前屏幕? 395 如何任意裁剪图片? 396 如何利用掩码位图制作透明图片? 397 如何实现图形的拉伸显示效果? 398 如何通过位图文件直接得到位图大小? 399 如何获取屏幕上某点的颜色? 400 如何设置屏幕上某点的颜色? 401 如何读取与显示JPG等格式图像文件? 402 如何转换图像文件大小? 403 如何转换图像文件格式? 404 如何将彩色图像转换成黑白图像? 405 如何实现图像的底片化效果? 406 如何实现图像的雾化效果? 407 如何实现图像的锐化效果? 408 如何实现图像的柔化效果? 409 如何实现图像的马赛克效果? 410 如何实现图像的百叶窗效果? 411 如何复制图像? 412 如何剪切图像? 413 如何粘贴图像? 414 如何实现画线拉伸效果? 415 如何绘制渐变色图形? 416 如何绘制渐变色文字? 第22章 网络 417 如何初始化Socket? 418 如何创建Socket? 419 如何处理网络监听Socket? 420 如何处理C/S互连? 421 如何处理C/S数据发送? 422 如何处理C/S数据接收? 423 如何实现无连接的通信? 424 如何实现有连接的通信? 425 如何用有连接方式实现网络会议? 426 如何获取网卡地址? 427 如何扫描端口状态? 428 如何进行连续的Ping? 429 如何获取主机名和IP地址? 430 如何搜索局域网内的计算机? 431 如何创建拨号网络? 432 如何检查电子邮件数量? 433 如何发送和接收电子邮件? 434 如何连接FTP服务器? 435 如何获取FTP服务器的文件列表? 436 如何向FTP服务器上传文件? 437 如何从FTP服务器下载文件? 438 如何查询HTTP站点? 439 如何查询FTP站点? 440 如何查询Gopher站点? 第23章 数据库 441 如何使用ODBC连接数据源? 442 如何使用ODBC实现应用程序与数据库记录的交换? 443 如何使用ODBC浏览数据库记录? 444 如何使用ODBC增加数据库记录? 445 如何使用ODBC删除数据库记录? 446 如何使用ODBC修改数据库记录? 447 如何使用ODBC排序数据库记录? 448 如何使用ODBC查询数据库记录? 449 如何使用SQL语句查询排序数据厍记录? 450 如何使用ODBC创建EXCEL文件? 451 如何使用ODBC读取EXCEL文件信息? 452 如何获取系统已经安装的ODBC驱动程序? 453 如何安装Visual C++.NET的MS Server服务管理器桌面引擎? 454 如何在Visual C++.NET创建 MS SQL Server数据库? 455 如何使用.NET类库访问数据库? 456 如何使用DAO新建数据库? 457 如何使用DAO打开数据库? 458 如何使用DAO关闭数据库? 459 如何使用DAO新建数据库表? 460 如何使用DAO打开数据库表? 461 如何使用DAO删除数据库表? 462 如何使用DAO浏览数据库表字段? 463 如何使用DAO增加数据库表字段? 464 如何使用DAO删除数据库表字段? 465 如何使用DAO新建数据库表查询? 466 如何使用DAO浏览数据库表查询? 467 如何使用DAO删除数据库表查询? 468 如何使用DAO自定义记录集类? 469 如何使用DAO浏览数据库记录? 470 如何使用DAO增加数据库记录? 471 如何使用DAO删除数据库记录? 472 如何使用DAO修改数据库记录? 473 如何使用DAO查询数据库记录? 474 如何使用DAO排序数据库记录? 475 如何使用DAO处理数据库异常? 476 如何判断数据集是否允许更新? 477 如何实现ADO对象与数据源的连接? 478 如何导入ADO动态链接库? 479 如何使用ADO对象浏览数据库记录? 480 如何使用ADO对象增加数据库记录? 481 如何使用ADO对象删除数据库记录? 482 如何使用ADO对象修改数据库记录? 483 如何使用ADO对象排序数据库记录? 484 如何使用ADO对象查询数据库记录? 485 如何使用ADO处理数据库异常? 486 如何存取数据库图像字段? 487 如何创建数据库操作事务? 488 如何在程序注册数据源? 489 如何创建ODBC数据源? 490 如何使用SQL模糊查询语句? 491 如何使用SQL语句检索时间段? 第24章 开发工具 492 如何设置条件断点? 493 如何设置堆栈大小? 494 如何产生全局惟一标识符? 495 如何删除项目文件的类? 496 如何打开和编辑二进制文件? 497 如何检测代码括号是否匹配? 498 如何查看一个宏的原始定义? 499 如何添加.1ib文件到当前项目? 500 如何调整对话框模板上的控件的Tab键顺序? 源码包含了封装的功能模块类以及测试类, 全部源码都可以用VS2020编译通过,请放心使用! 友情提示,为了兼顾一些旧代码,预编译头文件用的是StdAfx.h,如果需要更换为最新的pch.h,请按照以下步骤操作: 1将StdAfx.h、StdAfx.cpp移出项目,并添加pch.h、pch.cpp 2选整个项目,项目-属性-C++-预编译头-预编译头文件:pch.h 3选单个pch.cpp文件,右键菜单,属性-C++-预编译头-预编译头:创建(/Yc) 4确保步骤2、3在所有配置(配置:Release、Debug,平台:Win32、x64,共四种组合)均设置成功 5源码所有使用StdAfx.h的地方,均要替换 实例010——使用Windows API创建程序窗口 实例011——使用AppWizard创建基于文档视图结构MFC应用程序框架 实例012——使用AppWizard建立对话框应用程序框架 实例013——实现查找、替换字符串 实例014——根据指定字符分割字符串 实例015——格式化字符串 实例016——CString字符串的类型转换 实例017——获取当前的日期、时间并格式化输出 实例018——计算某日为星期几 实例019——计算两个时间点的时间间隔 实例020——使用CStringArray类创建和使用字符串数组 实例021——使用CPtrList类创建和使用链表 注意:指定数字的地方若以下列字符结尾,则乘以相应的数字:b=512;另一种方法则是使用命令或者脚本,这样的好处是可以实现自动化,而不需要每次的手动编辑。上述命令是指使用dd命令把0x80写入到temp.elf文件的第27个字节处。可能我们很少会改写二进制文件,可是当我们要改写的时候,我们需要知道怎么做!dd:用指定大小的块拷贝一个文件,并在拷贝的同时进行指定的转换。比如:010 Editor,UltraEdit。想知道更多的dd命令解释,请自行百度。 如果使用C++写一段内存的替换,只使用简单的比较或是memcpy等操作,来实现替换一个文件内容,写起来还是有点麻烦的: 首先要把文件内容读取到字符串,然后从文件的开头字符进行比较,直到匹配上字符后,基于查找到的问题,替换内容,然后再回写到文件。 4.列举你了解的那些数据类型的值转换为布尔值为False。 5.看代码写结果; 6.让用户输入一段文本,请实现将文本的敏感词 奥利给、我恁爹替换为***,最后并输出替换后的文本。 7.有变量name = " Ken Nb "完成如下操作: 8.如何实现字符串的翻转? 9.有字符串s = "123a4b5c" 10.使用while循环实现对字符串message = "伤情最是晚凉天,憔悴厮人不堪言"每个字符进行输出。 11.使用for循环实 // 创建、写入方式打开文件 CFile file; file.Open("C://TestFile.txt", CFile::modeWrite | CFile::modeCreate); // 写入文件 memset(WriteBuf, 'a', sizeof(WriteBuf)); file.Write(WriteBuf, sizeof(WriteBuf)); // 关闭文件 file.Close(); // 只读方式打开文件 file.Open("C://TestFile.txt", CFile:. 打开一个文件文件使用方式含义r只读(文本文件)w只写(文本文件)为输出数据,,打开文本文件(建立新文件)a追加(文本文件)rb只读(二进制文件)wb只写(二进制文件) 为输出数据,打开二进制文件(建立新文件)ab追加(二进制文件)r+读写w+读写为了读和写,建立一个文本文件a+读写为了读和写,打开一个文本文件rb+读写为了读和写,打开一个二进制文件wb+读写为了读和写,建立一个新的 二进制文件a... 文件的打开模式 w 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。 w+ 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。 wb 只写方式打开或新建一个二进制文件,只允许写数据。 wb+ 读写方式打开或建立一个二进制文件,允许读和写。 r 打开只读文件,该文件必须存在,否则报错。 r+ 打开可读写的文件, 在 Web 开发,当我们处理文件时(创建,上传,下载),经常会遇到二进制数据。另一个典型的应用场景是图像处理。这些都可以通过 JavaScript 进行处理,而且二进制操作性能更高。不过,在 JavaScript 有很多种二进制数据格式,会有点容易混淆。 [root@lab101 opt]# hexdump -C b_head 00000000 02 00 00 00 00 00 00 00 4c 0f 00 00 00 00 01 00 |........L.......| 00000010 00 08 |..| 00000012 原始数据是一个二进制文件,其里面的inode是0 这几天还在做代码生成,发现其实谷歌也在做字符替换类型的代码生成,完全加入不了其他AI方法,因为不稳定,所以实用的代码生成还都是字符替换,所以,总结一下C++字符替换的方法。在 C++ ,可以使用字符串流、字符数组、STL 的算法、正则表达式等方法来实现字符串的替换。根据实际需要,可以选择适合的方法来实现字符串的替换。晚安好梦! 本程序要自己创建个文本格式的输入文件a1.txt,编译后能将文本文件前255字节以内的字符转换成相应的AscII码值的二进制表示,并存入输出文件a2.txt。然后再将二进制文件还原并存入a3.txt文件。具体代码如下:#include #include #include #define NSIZE 8void print_2(int val2);/***********文本文件二进制*****... 本文转载http://blog.csdn.net/l_andy/article/details/24300827 主要是通过使用CArchive类作为读写操作 CArchive ar(&file, CArchive::store);//根据打开的文件,创建文件串行化对象  用来写      CArchive ar(&file, CArchive::load);//根