2017-09-13 46 views
1

我正在處理一個小型項目,我必須管理文件I/O(這是我剛剛退出的新項目)。我將使用unicode作爲字符集的WIN32 API,因此使用寬字符存儲所有文件數據,並且程序中的所有字符串均使用std :: wstring存儲。這是函數讀取的部分,並返回字符串:WCHAR *的結尾包含垃圾

  //Get the string from file and return it 
      //(nChars is the amount of characters to read) 
      WCHAR * resultBuffer = new WCHAR[nChars]; 
      file.read(resultBuffer, nChars); 
      std::wstring result = resultBuffer; 
      delete[] resultBuffer; 
      return result; 

但是我注意到,結果在結尾處包含了一堆亂碼(整個字符串被正確讀取文件,但在附加亂碼結束)。經過進一步檢查,我注意到這些字符也出現在resultBuffer被分配之後。現在,如果它們會被覆蓋,但似乎會被附加,並且它們會被複制(因爲結果會獲得比預期更多的元素),這會導致在以後使用它們時出現很多問題,所以這不會成爲問題。我設法通過增加一些來解決問題:

  //Get the string from file and return it 
      WCHAR * resultBuffer = new WCHAR[nChars]; 
      file.read(resultBuffer, nChars); 
      std::wstring temp = resultBuffer; 
      std::wstring result; 
      for (INT i = 0; i < nChars; i++) { //NOTE: This shouldn't be necessary 
       result.push_back(temp.at(i)); 
      }    
      delete[] resultBuffer; 
      return result; 

這解決了問題,但我覺得好像不應該需要。我懷疑它可能與讀函數(std :: wifstream :: read())的工作方式有關,但我查看了它的文檔,發現沒有線索。我沒有太多的使用unicode和寬字符的經驗,所以它可能是顯而易見的東西,我錯過了,但我真的在線索。任何人有任何想法?這就是resultBuffer在read()被調用後的樣子(stackoverflow將它們打印爲某些中東字符,但它們在visual studio中顯示爲一些亞洲字符)。

  • ResultBuffer的L「\\。\ DISPLAY1﷽﷽☐☐كي헏✀耀☐☐☐☐☐☐☐☐☐☐☐☐☐☐☐☐☐☐☐☐☐☐☐☐☐☐☐☐ ☐」的wchar_t *

編輯: 由於雷米勒博和mksteve如答案藏漢提供卓越的解釋!這是工作代碼:

  //Get the string from file and return it 
      std::wstring result; 
      result.resize(nChars); 
      file.read(&result[0], nChars); 
      return result; 

回答

3

您所呼叫的std::wstring構造函數需要一個空值終止字符串wchar_t*,但你是不是空終止您的緩衝區。分配+1更WCHAR並將其設置爲0:

WCHAR * resultBuffer = new WCHAR[nChars+1]; 
file.read(resultBuffer, nChars); 
resultBuffer[nChars] = L'\0'; 
std::wstring result = resultBuffer; 
delete[] resultBuffer; 
return result; 

另外,如果您構建std::wstring時指定的緩衝區長度,你不需要空終止:

WCHAR * resultBuffer = new WCHAR[nChars]; 
file.read(resultBuffer, nChars); 
std::wstring result(resultBuffer, nChars); 
delete[] resultBuffer; 
return result; 

無論哪種方式,你應該使用std::vector來管理內存緩衝區,而不是new[]/delete[]手動使用:

std::vector<WCHAR> resultBuffer(nChars+1); 
file.read(&resultBuffer[0], nChars); 
resultBuffer[nChars] = L'\0'; 
return std::wstring(resultBuffer.data()); 

std::vector<WCHAR> resultBuffer(nChars); 
file.read(&resultBuffer[0], nChars); 
return std::wstring(resultBuffer.data(), nChars); 

或者,你可以擺脫緩衝乾脆而直接讀入std::wstring本身:

std::wstring result; 
result.resize(nChars); 
file.read(&result[0], nChars); // or result.data() in C++17 
return result; 
+0

中讀取的字節數之後以null結尾。使用C++ 17,您還可以立即寫入到「std :: wstring」中,通過傳遞結果['std :: string :: data()'](http://en.cppreference.com/w/cpp/string/basic_string/data)寫入'file.read()'。 – IInspectable

+1

在使用C++ 17之前,可以使用字符串的'operator []'。 –

+0

如果您使用'std :: vector',則不需要自己設置終結符,它將被默認初始化爲零。 –

1

當你讀取n從緩衝區中的字符,該機制創建std::string是使用尺寸構造

file.read(resultBuffer, nChars); 
std::wstring temp(resultBuffer, nChars); 

這略微距離差空終止自己的輸入,因爲它允許一個ResultBuffer包括L「\ 0」,成爲帕t的新字符串。如果這是不正確的,那麼確保數據在從file.read