windows中Read函数引发数据异常的问题
【摘要】
在Window C/S开发中少不了客户端与服务端数据通信的情况,每当客户端从服务端获取数据时会将数据读到本地本件或缓存中,例如通过CInternetFile类的Read函数会将网卡缓存中的数据读入到制定的缓存中;在某APP通讯录中会很频繁地用到该函数去读取数据,然而由于当初没有细究该函数的使用情况,会意想不到地造成了客户端UI显示的内容异常,比如读取xml格式的内容时出现多余的字符串或者显示的内容为空。为此,本文将结合该函数的源码和MSDN资料以及实验结果来说明该函数的正确使用方法。
【关键字】
Windows、CInternetFile、Read
【类别】
大分类:软件; 小分类:代码优化
一、引出问题
在某APP中查看组织通讯录时有的成员节点或者部门节点有时候会出现多余的字符串或者为空信息,当出现该情况时刷新一下数据又正常了;后续该现象复现的频率就很高了,几乎每次都会发生了。接下来,就针对该情况做数据分析。
二、发现问题
由于该模块的数据量比较大,单步调试的话不好弄,只能通过添加打印日志来跟踪。首先,在数据显示之前将名称、职位等信息打印出来,当出现该异常时取出日志,发现显示的数据本身就有问题,接着对比一下数据库里的内容,发现数据库里存的数据也是异常数据,这个时候就需要在解析数据那块添加打印日志了,当初发现数据解析模块没有对局部变量进行初始化操作,想当然地以为是未初始化引起的,但是当对相关变量初始化操作后进行试验,该异常情况依旧出现,所以为初始化操作不是问题的原因;这个时候又开始怀疑是数据解析方法的问题,但是逆推思想推翻了该猜疑,要是是数据解析的方法有问题的话,那么所有的数据显示会异常,而不是只有少数部分数据异常;既然排除了数据解析方面,那么在数据解析之前对数据进行打印,后来实验发现确实是输入的数据有问题;而这个数据的来源是从另一个线程发送过来的,所以只能去数据源的线程查找问题的根源了。
三、找出原因
通过阅读代码流程可知数据的来源于CInternetFile::Read()函数获取到的数据,代码如下:
string strHtml = "";
char tChars[+] = {};
while ((pFile->Read((void*)tChars, )) > )
{
strHtml += tChars;
memset(tChars, , + );
}
初步看着这代码,觉得是没啥问题的,每次读取到的数据放在tChars数组里,下次读取数据之前都会置零处理,这样看似完美的流程是不会被怀疑的,可事实就是让人陷阱这个“美人计”中,导致数据异常。通过MSDN资料了解到,Read()函数第一个参数用于存放读取到的数据,第二个参数为每次读取数据的长度,它的返回值为实际读取到的数据。到此,对问题有点眉头了,也就是说Read函数第一个参数存储的是数据内容,其长度为第二个参数值;当第二个参数值和该函数的返回值不相等时,那么第一参数存储的内容就有一些内容时多余的,假设第二个参数值为InputValue,返回值为OutputValue,那么tChars数组中存有(InputValue—OutputValue)个多余的字符,并且是在数组的后面。带着这个疑惑,进入Read()函数源码分析,发现该函数调用的是InternetReadFile()函数,此函数最后一个参数就是实际读取数据的长度,为了证实我们对Read()函数第二个参数和返回值不相等的假设,那么就在该处添加断点进行调试。最后,通过实验证实了上述假设,InternetReadFile()函数返回的实际数据长度与Read()函数第二个参数值有时候会不相等。此外,通过实验发现一个有趣的问题,就是Read()函数读取到的数据若是存有多余的字符或者字符串的话,那这些多余的字符或者字符串就是Read()函数读取到的有效数据内容最后字符或字符串的重复。现在问题缘由被找到了,接下来就如何解决问题了,请看后续部分。
四、解决问题
既然Read()函数读取到内容有两个数据长度值,那么我们就采用实际数据长度值即可,将每次读取到的数据再进行一次拷贝操作即可,方法如下:
string strHtml = "";
char tChars[ + ] = {};
char tCharsTmp[ + ] = {};
while (nReadSize > )
{
nReadSize = ;
memset(tChars, , + );
memset(tCharsTmp, , + );
nReadSize = pFile->Read((void*)tCharsTmp, );
memcpy(tChars, tCharsTmp, nReadSize);
strHtml += tChars;
}
或者
while (nReadSize > )
{
nReadSize = pFile->Read((void*)tCharsTmp, );
strHtml.assign(tCharsTmp, , nReadSize);
}
通过该方式的修改后进行试验操作,没有发现组织通讯录中存在数据显示异常的问题了;因此,问题得解。
五、得出结论
在引用此类API函数时最好要考虑到其数据的实际长度值,然后通过其实际的数据长度来拷贝出新的一份数据,这样可以去除原有数据中多余的内容。
------20191228闪
windows中Read函数引发数据异常的问题的更多相关文章
- 类中成员函数与数据成员private/pubic/protected
类中成员函数与数据成员private/pubic/protected
- 在MS单元测试中引发期望异常
首先准备一个引发异常的方法. public static void ThrowException() { throw new ArgumentException(); } 然后在单元测试项目中,写下测 ...
- antd pro中如何使用mock数据以及调用接口
antd pro的底层基础框架使用的是dva,dva采用effect的方式来管理同步化异步 在dva中主要分为3层 services models components models层用于存放数据 ...
- 关于调试器中int3断点引发异常的思考
INT3断点 INT3断点是利用0Xcc指令实现的,cpu在执行0xcc指令时会引发断点异常调试器会捕捉这个异常. INT3断点引发的异常属于陷阱型异常,在执行完0xcc指令后eip指向下一条指令.但 ...
- windows环境下nutch2.x 在eclipse中实现抓取数据存进mysql详细步骤
nutch2.x 在eclipse中实现抓取数据存进mysql步骤 最近在研究nutch,花了几天时间,也遇到很多问题,最终结果还是成功了,在此记录,并给其他有兴趣的人提供参考,共同进步. 对nutc ...
- WPF关于“在“System.Windows.Markup.StaticResourceHolder”上提供值时引发了异常。”问题解决办法
在WPF中添加样式,在MainWindow.xaml使用自定义按钮FButton时报错,报错信息如下: "System.Windows.Markup.XamlParseException&q ...
- Linux启动kettle及linux和windows中kettle往hdfs中写数据(3)
在xmanager中的xshell运行进入图形化界面 sh spoon.sh 新建一个job
- 选择目录,选择文件夹的COM组件问题。在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式。请确保您的 Main 函数带有 STAThreadAttribute 标记。 只有将调试器附加到该进程才会引发此异常。
异常: 在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式.请确保您的 Main 函数带有 STAThreadAttribute 标记. 只有将调试器附加到该进程才会引发此异常. ...
- System.Windows.Forms.AxHost.InvalidActiveXStateException”类型的异常在 ESRI.ArcGIS.AxControls.dll 中发生,但未在用户代码中进行处理
private void CopyAndOverwriteMap() { //IObjectCopy接口变量申明 IObjectCopy objectCopy = new ObjectCopyClas ...
随机推荐
- package.json(node)中,多个命令行合并一条
1. ‘&’ 并行执行顺序,同时执行 "dev":"node test.js & webpack" 2.'&&'继发顺序,执行前 ...
- Lambda如何实现条件去重distinct List,如何实现条件分组groupBy List
条件去重 我们知道, Java8 lambda自带的去重为 distinct 方法, 但是只能过滤整体对象, 不能实现对象里的某个值进行判定去重, 比如: List<Integer> nu ...
- 手把手教你快速使用数据可视化BI软件创建全球经济贸易分析大屏
灯果数据可视化BI软件是新一代人工智能数据可视化大屏软件,内置丰富的大屏模板,可视化编辑操作,无需任何经验就可以创建属于你自己的大屏.大家可以在他们的官网下载软件. 本文以全球经济贸易分析大屏为例 ...
- C#设计模式学习笔记:(16)观察者模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7928521.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第四个模式--观 ...
- jni和线程
JNI官方规范中文版——在程序中集成JVM需要注意的JNI特征 翻译 我们已经讨论了JNI在写本地代码和向本地应用程序中集成JVM时的特征.本章接下来的部分分介绍其它的JNI特征. 8.1 JNI和线 ...
- C++ 实现string转BYTE
用于将形如"0x1A"的string转成BYTE类型 代码如下, 有问题欢迎指出 bool str2byte(const std::string &str, BYTE &a ...
- TP6文档-邓士鹏
2019年5月11日 - 教程为您提供<ThinkPHP6.0极速入门(视频教程)>之 TP6的目录结构 章节的在线实战教程供您学习,你可以进行笔记.提问.讨论和资料下载 https:// ...
- 硬件知识整理part3--电阻在单片机系统中的应用
邦有道,如矢:邦无道,如矢. --孔子 电阻在电路中主要功能是限流和分压等等.在单片机系统中自然也是. 电阻作为限流应该是最常用的应用之一,对于单片机外围设计来说,电阻的应用非常重要,在很多时候,我 ...
- 清北学堂—2020.1提高储备营—Day 3(图论初步(二))
qbxt Day 3 --2020.1.19 济南 主讲:李奥 目录一览 1.图论(kruskal算法,最短路径算法,拓扑排序) 总知识点:图论 一.kruskal算法 1.目的:求图的最小生成树 2 ...
- Java 8 函数式编程
今天打开Oracle Java官网一看,Java已经更新到 13 了 https://www.oracle.com/technetwork/java/javase/jdk-relnotes-index ...