【问题标题】:File read write using MFC CFile使用 MFC CFile 进行文件读写
【发布时间】:2015-03-17 18:49:21
【问题描述】:

我想知道为什么下面的代码没有将正确的数据写入文件。如果我将缓冲区大小更改为更大,则此代码可以正常工作。

对于下面的代码,如果我尝试读取小于 500 字节的文件,效果很好,但对于更大的文件,我必须增加缓冲区。我在阅读循环中缺少什么?

  const int iBuffSiz = 500;
  char chBuffer[iBuffSiz];
  memset(chBuffer, 0, sizeof(chBuffer));
    CFile file;
  CFile fileO;

  if(file.Open(XML_FILE_NAME, CFile::modeRead | CFile::typeBinary) == FALSE)
  {
    return;
  }

  if(fileO.Open(XML_FILE_NAME_O, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary) == FALSE)
  {
    return;
  }

  while(file.Read(chBuffer, iBuffSiz) > 0)
  {
    try{
      UINT iCount = strlen(chBuffer);
      fileO.Write(chBuffer, iCount);
    }
    catch (CFileException *exp)
    {
      TCHAR szCause[255];
      exp->GetErrorMessage(szCause, 255);
    }
  }

  //Closing file handle and socket after complete file send
  file.Close();
  fileO.Close();

【问题讨论】:

  • 您以 CFile::typeBinary 的形式打开输入文件,但使用 strlen() 来获取任何长度。
  • 这有点误导,@plaintext,因为CFile::typeBinary 与这些问题无关。问题在于,无论有没有该标志,OP 都不能保证缓冲区内容是一个以 NUL 结尾的字符串,这是使用strlen() 所必需的。相反,检查 CFile 的文档,我认为它可以告诉你它读取了多少字节。最后,还有两个提示:有更好的方法来复制文件(搜索网络!),捕获然后完全忽略异常是非常有害的。

标签: c++ mfc


【解决方案1】:

CFile::Read 不会空终止缓冲区,因此缓冲区的strlen 可以大于缓冲区,它会导致缓冲区溢出。有一种方法可以解决这个问题,但strlen 仍然无法处理二进制文件,这次缓冲区太短了。所以最好使用CFile::Read返回的值

UINT iCount;
while( ( iCount = file.Read(chBuffer, iBuffSiz) ) > 0 )
{
   try
   {
      fileO.Write(chBuffer, iCount);
   }
   catch (CFileException *exp)
   {
      TCHAR szCause[255];
      exp->GetErrorMessage(szCause, 255);
   }
}

【讨论】:

  • 这很完美,原因很明显。谢谢。只有一件事我很想知道。如果我将while循环更改为'while(iCount = file.Read(chBuffer,iBuffSiz)> 0)'为什么它不能将正确的数据写入输出文件。 >0 假设执行与上述代码相同的工作,while 循环将运行直到值为 true。这里有什么问题。
  • 它需要另一组括号来携带=运算符的结果。我用> 0 编辑了答案。我很确定 CFile::Read 不会返回负数,但最好是安全的。之前也很混乱。
【解决方案2】:

同意 Barmark 的观点,即 CFile::Read 返回的计数可能超过指定的缓冲区大小

我还有一点是

*** 您需要在将缓冲区写入另一个文件后清除缓冲区,因为它指向您已经写入目标文件的字符串,因此您可能无法获得所需文件的精确副本。

  while(file.Read(chBuffer, iBuffSiz-1) > 0)
  {
    try{
      UINT iCount = strlen(chBuffer);
      fileO.Write(chBuffer, iCount);
      memset(chBuffer, 0, sizeof(chBuffer));
    }
    catch (CFileException *exp)
    {
      TCHAR szCause[255];
      exp->GetErrorMessage(szCause, 255);
    }
  }

【讨论】:

  • CFile::Read 将返回您指定为其第二个参数的最大字节数,它的 strlen 位于非空终止的缓冲区上,导致未定义的行为。此外,如果您使用 CFile::Read 返回值来确定您可以使用多少缓冲区以及必须丢弃多少缓冲区,则无需清除缓冲区。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-06
相关资源
最近更新 更多