飞鸽传书里CFile::Read读文件问题解决方案

分类: VC/MFC

我定义了一个结构

typedef struct tag_HOSTINFO
{
   char szHostName[64];
   DWORD dwIP;
   DWORD dwPort;
}HOSTINFO, *PHOSTINFO;

然后我填充这个结构,将N个结构信息写入文件

接着我用下面的方法读出写入文件的数据:
CFile f;
f.Open(.....)

PHOSTINFO pInfo = new HOSTINFO; //申请内存
ZeroMemory(pInfo, sizoef(HOSTINFO); // 用0填充新申请的空间

while ( f.Read(pInfo, sizeof(HOSTINFO)) == sizoef(HOSTINFO)) // 将数据读入内存
{
    AddToList((void*)pInfo); // 将读出来的数据指针放入链表

    PHOSTINFO pInfo = new HOSTINFO; // 再申请内存,为下一次读数据做准备
    ZeroMemory(pInfo, sizoef(HOSTINFO); // 如果这里改了变量名的话,下一次read
                                       // 就没法读数据到新的内存了

}
delete pInfo;// 删除多申请的一次内存
...
f.Close();

可是当我调试的时候却发现,new HOSTINFO成功申请了内存,可是当f.Read的时候
pInfo不仅读出来的值不对而且pInfo本身的值被修改了,类似 0xcccccc.的东西

后来我改变了写法:

HOSTINFO tInfo;
ZeroMemory(&tInfo, sizeof(HOSTINFO));
while ( f.Read(&tInfo, sizeof(HOSTINFO)) == sizoef(HOSTINFO))
{
    PHOSTINFO pInfo = new HOSTINFO;
    ZeroMemory(pInfo, sizoef(HOSTINFO);
   
    memcpy(pInfo, &tInfo, sizeof(HOSTINFO));
    // do something
}

这个时候,我发现pInfo没有被修改而且值也对,我看了MSDN:
virtual UINT Read(
void* lpBuf,
UINT nCount );

Parameters:
lpBuf
Specifies the pointer to the user-supplied buffer that is to receive the data read from the file.

nCount
Specifies the maximum number of bytes to be read from the file. For text-mode files, carriage return–linefeed pairs are counted as single characters.

Return Value
The number of bytes transferred to the buffer. Note that for all CFile classes, the return value may be less than nCount if the end of file was reached.

从这上面的描述来看,我new 出来的内存应该也是可以的,可为什么会被修改呢?
我一直搞不明白,后来在vckbase.com的论坛上问了问,我才发现一个不应该出现的错误:

在这段代码里面,我愿意是这样一个流程:

申请内存

while ( 读数据 )
{
   将读出来的数据指针加入到链表
   再申请内存【准备接受下一次读的数据】
}

删除最后一次多申请的内存【至于前面申请的我会在程序退出时一块释放】

论坛上一些兄弟说因为内循环和外循环的变量相同导致了调试结果不正确,可是我这里因为要循环读数据,
那么如果修改了内循环的变量名称,就会导致下一次while循环无法将新读的数据放到新申请的内存,后来
有个兄弟提醒我“ 循环内变量不要重新定义,每次new即可”,我猛然发现,这里写错了:

在while循环里面
while ( f.Read(&tInfo, sizeof(HOSTINFO)) == sizoef(HOSTINFO))
{
    PHOSTINFO pInfo = new HOSTINFO;
    ZeroMemory(pInfo, sizoef(HOSTINFO);

    memcpy(pInfo, &tInfo, sizeof(HOSTINFO));
    // do something
}

这个

PHOSTINFO pInfo = new HOSTINFO;

应该改为:

pInfo = new HOSTINFO;

因为如果前面再加一个PHOSTINFO就相当于重新定义了一个变量,而我的本意是要用同一个指针在完成一次读数据之后,指向新分配的内存,然后再将新的数据读入到新分配的内存,如果重新定义的话,显然是违背了这个意思。
而如果不重新定义的话,在while循环里面pInfo = new HOSTINFO;
只是把外面定义的指针pInfo指向了新的内存,这样就能达目的。

后来一个兄弟提出了这样的读数据方法,我觉得很有借鉴意义:

int iRecordCount = file.GetLength()%sizeof(HOSTINFO)?file.GetLength()/sizeof(HOSTINFO) + 1 : file.GetLength()/sizeof(HOSTINFO); //根据文件长度确定结构个数


PHOSTINFO pInfo[iRecordCount];
//分配
for ( int i = 0; i < iRecordCount; i++ )
{
   pInfo = new HOSTINFO;
   ZeroMemory(pInfo, sizeof(HOSTINFO));
}
file.Read(pInfo[0], sizeof(HOSTINFO) * iRecordCount); //可以一次性读完

这个根据文件长度和结构大小确定结构个数,然后根据结构个数和大小循环分配内存,最后,一次性读完所有数据到分配的内存,这个方法相当不错。不过,需要注意的是, CFile::Read应该有最大读取数据的限制的,如果超过了,也可能导致读取失败。


另外读写文件语句:

if   (cFile.Open(sFileName,   CFile::modeRead   |   CFile::typeBinary,   &e))  
  {  
  BYTE*   pBuff   =   new   BYTE[cFile.GetLength()];  
   
  if   (cFile.Read(pBuff,   cFile.GetLength())   >   0)  
  {  
  if   (LoadFromBuffer(pBuff,   cFile.GetLength()))  
  bResult   =   true;  
  }   
  delete   []   pBuff;  
  }


不同文件读取的方式不同:

rmv文件要用二进制打开的,试试:
CFile file("c:\\test.rmv", CFile::modeRead|CFile::typeBinary );

你应该用二进制方式打开文件,因为你这个文件不是文本文件,而是wma,应该是二进制的。
if(!myFile.Open( _T("c:\\1.wma"),CFile::modeRead|CFile::typeBinary,NULL))


原文:飞鸽传书里CFile::Read读文件问题解决方案


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值