2016-11-04 57 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