2016-11-04 63 views
0

简介:

我正在从文本文件中读取ReadFile。传递到ReadFile的缓冲区将被发送到标准输出cout。标准输出被重定向到一个文本文件。文件大小比应该大,增加了新的行数

问题:

虽然我的代码“作品”,不会丢失数据,生成的文件比原来的大。

在记事本中打开时,一切似乎都很好,但在​​中打开时,我可以清楚地看到添加了多余的行。这些行是新行(\n)。

MVCE重现此行为的内容在下面提交。

#include <iostream> 
#include <Windows.h> 

int main() 
{ 
    HANDLE hFile = ::CreateFile("C:\\123.txt", 
     GENERIC_READ, 
     FILE_SHARE_READ | 
     FILE_SHARE_WRITE | 
     FILE_SHARE_DELETE, 
     NULL, 
     OPEN_EXISTING, 
     FILE_ATTRIBUTE_NORMAL, 
     NULL); 

    if (INVALID_HANDLE_VALUE == hFile) 
     return ::GetLastError(); 

    char buffer[256]; 
    DWORD bytesRead = 1, // dummy value so while loop can work 
     bytesWritten = 0; // needed for WriteFile, not for cout version 

    //======== so WriteFile outputs to console, not needed for cout version 
    HANDLE hStandardOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); 

    if (INVALID_HANDLE_VALUE == hStandardOutput) 
    { 
     std::cout << "GetStdHandle error code = " << ::GetLastError() << std::endl; 
     ::CloseHandle(hFile); 
     return ::GetLastError(); 
    } 
    //============================ 
    while(bytesRead) 
    { 
     // '\0' terminate buffer, needed for cout only 
     ::memset(buffer, '\0', sizeof(buffer)); 

     if (!::ReadFile(hFile, 
      buffer, 
      sizeof(buffer) - 1, // - 1 for '\0', not needed when using WriteFile 
      &bytesRead, NULL)) 
     { 
      std::cout << "ReadFile error code = " << ::GetLastError() << std::endl; 
      break; 
     } 
     /*============= Works fine 
     if(!::WriteFile(hStandardOutput, buffer, bytesRead, &bytesWritten, NULL)) 
     { 
      std::cout << "WriteFile error code = " << ::GetLastError() << std::endl; 
      break; 
     }*/ 
     //------------- comment out when testing WriteFile 
     std::cout << buffer; // extra lines... 
     // std::cout.write(buffer, bytesRead); // extra lines as well... 
     //---------------------------------------- 
    } 
    ::CloseHandle(hFile); 
    return 0; 
} 

问题:

是什么原因造成上述现象?如何解决它?

我的努力解决问题:

当我键入这个职位,我漫无目的的谷歌搜索,希望能有些线索出现。

我怀疑问题在于输出\n时,似乎Windows也插入\r,但我不确定。

+0

这都没有关系文件。只有'std :: cout <<'如何工作 – RbMm

+0

@RbMm:你能解释一下,还是提供一个解释为什么会发生这种情况的链接?谢谢你的评论(我没有忘记你的其他IO完成端口的答案,我正在与此问题平行)。 – AlwaysLearningNewStuff

+0

'cout'不能用于处理原始二进制数据。绝对正常,他可以添加额外的'\ r'或'\ n'字符。您将文件读取为原始二进制数据,但尝试将其写入格式化的字符串数据。不奇怪,结果不匹配。尝试使用WriteFile并在这种情况下进行比较。或确定你想要什么 – RbMm

回答

1

\n字符对STL字符流有特殊的含义。它代表一个换行符,在输出时将被转换为平台特定的换行符。这是这里讨论:

Binary and text modes

文本流是由为行(零个或多个字符加上终止'\n')字符的有序序列。最后一行是否需要终止'\n'是实现定义的。汉字可能要添加,更改或输入和输出删除,以符合约定的OS表示文本(特别是ç流在Windows操作系统转换\n\r\n输出,并转换\r\n\n上输入)。

所以很可能std::cout输出\r\n当它被赋予\n,即使前一\r也被给,因而\r\n的输入可能成为上输出\r\r\n。在Windows上,这不是标准化的行为,单个应用程序如何处理裸CR字符。他们可能会被忽略,或者他们可能被视为换行符。就你而言,这听起来像后者。

有一个在二进制模式下使用std::cout没有标准方式,以便\n\n而不是作为\r\n输出。但是,请参阅How to make cout behave as in binary mode?,其中提供了一些可能的方法,您可以在Windows上以二进制模式输出std::cout输出,具体取决于您的编译器和STL实现。或者,您可以尝试使用std::cout.rdbuf()替换您自己的std::basic_streambuf执行二进制输出到控制台的对象。

话虽这么说,你的代码是处理数据缓冲区的方式是有点过,它应该看起来更像这个代替(不考虑上述信息):

#include <iostream> 
#include <Windows.h> 

int main() 
{ 
    HANDLE hFile = ::CreateFile("C:\\123.txt", 
     GENERIC_READ, 
     FILE_SHARE_READ | 
     FILE_SHARE_WRITE | 
     FILE_SHARE_DELETE, // why?? 
     NULL, 
     OPEN_EXISTING, 
     FILE_ATTRIBUTE_NORMAL, 
     NULL); 

    if (INVALID_HANDLE_VALUE == hFile) 
     return ::GetLastError(); 

    char buffer[256]; 
    DWORD bytesRead, bytesWritten, err; 

    //======== so WriteFile outputs to console, not needed for cout version 
    HANDLE hStandardOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); 

    if (INVALID_HANDLE_VALUE == hStandardOutput) 
    { 
     err = ::GetLastError(); 
     std::cout << "GetStdHandle error code = " << err << std::endl; 
     ::CloseHandle(hFile); 
     return err; 
    } 

    //============================ 
    do 
    { 
     if (!::ReadFile(hFile, buffer, sizeof(buffer), &bytesRead, NULL)) 
     { 
      err = ::GetLastError(); 
      std::cout << "ReadFile error code = " << err << std::endl; 
      ::CloseHandle(hFile); 
      return err; 
     } 

     if (bytesRead == 0) // EOF reached 
      break; 

     /*============= Works fine 
     if (!::WriteFile(hStandardOutput, buffer, bytesRead, &bytesWritten, NULL)) 
     { 
      err = ::GetLastError(); 
      std::cout << "WriteFile error code = " << err << std::endl; 
      ::CloseHandle(hFile); 
      return err; 
     } 
     */ 

     //------------- comment out when testing WriteFile 
     std::cout.write(buffer, bytesRead); 
     //---------------------------------------- 
    } 
    while (true); 

    ::CloseHandle(hFile); 
    return 0; 
} 
+0

感谢您回答我的问题。这是深夜,所以我想睡觉。我已经设法测试你的代码,它显示了和我在OP中一样的行为。看来我必须坚持使用'WriteFile'。我将在“WriteFile”解决之前“争取”一段时间。再次谢谢你。 – AlwaysLearningNewStuff

+0

我决定使用'WriteFile',谢谢你的帮助。 – AlwaysLearningNewStuff