2015-08-19 152 views
0

當我嘗試將文件讀取到緩衝區時,它總是將隨機字符附加到緩衝區的末尾。使用fstream讀取文件

char* thefile; 
    std::streampos size; 

    std::fstream file(_file, std::ios::in | std::ios::ate); 
    if (file.is_open()) 
    { 
     size = file.tellg(); 
     std::cout << "size: " << size; 
     thefile = new char[size]{0}; 

     file.seekg(0, std::ios::beg); 
     file.read(thefile, size); 
     std::cout << thefile; 
    } 

    int x = 0; 

雖然我在我的文件原文是:「你好」 輸出變成了:「helloýýýý««««««««þîþîþ」

誰能幫我一下,這裏發生了什麼?由於

+0

讀取函數的返回值是什麼? –

+0

@DanielJour'stream.read(...)'返回流本身。 –

+0

確實,我錯誤地認爲它會返回'gcount()'值,這實際上應該檢查。 –

回答

1

如果文件沒有以ios::binary模式打開,則不能認爲tellg()返回的位置會給出您將要讀取的字符數。文本模式操作可能會對流程執行一些轉換(f.ex:在Windows上,它將在「\ n」中轉換文件中的「\ r \ n」,因此您可能會發現大小爲2,但只能讀取1)

無論如何,read()不會添加空終止符。

最後,由於必須添加空終止符,您必須分配比您期望的大小多一個字符。否則,您在添加緩衝區時會發生緩衝區溢出。

您應該驗證有多少個字符是和gcount(),並相應地爲您的字符串設置一個空終止符。

thefile = new char[size + 1]{0}; // one more for the trailing null 
    file.seekg(0, std::ios::beg); 
    if (file.read(thefile, size)) 
     thefile[size]=0;    // successfull read: all size chars were read 
    else thefile[file.gcount()]=0; // or less chars were read due to text mode 
-1

這裏的閱讀您的收藏更好的辦法:

#include <vector> 
#include <fstream> 
#include <iostream> 
#include <sstream> 
#include <string> 
#include <cstdint> 
#include <iterator> 

template<class T> 
void Write(std::string const & path, T const & value, std::ios_base::openmode mode) 
{    
    if (auto stream = std::ofstream(path, mode)) 
    { 
     Write(stream, value); 

     stream.close(); 
    } 
    else 
    { 
     throw std::runtime_error("failed to create/open stream"); 
    }  
} 

template<class T> 
void Write(std::ostream & stream, T const & value) 
{ 
    std::copy(value.begin(), value.end(), std::ostreambuf_iterator<char>(stream)); 

    if (!stream) 
    { 
     throw std::runtime_error("failed to write"); 
    } 
} 

template<class T> 
void Read(std::istream & stream, T & output) 
{ 
    auto eof = std::istreambuf_iterator<char>(); 

    output = T(std::istreambuf_iterator<char>(stream), eof); 

    if(!stream) 
    { 
     throw std::runtime_error("failed to read stream"); 
    } 
} 

template<class T> 
void Read(std::string const & path, T & output) 
{    
    if (auto stream = std::ifstream(path, std::ios::in | std::ios::binary)) 
    { 
     Read(stream, output); 

     stream.close(); 
    } 
    else 
    { 
     throw std::runtime_error("failed to create stream"); 
    }   
} 


int main(void) 
{ 
    // Write and read back text. 

    { 
     auto const s = std::string("I'm going to write this string to a file"); 

     Write("temp.txt", s, std::ios_base::trunc | std::ios_base::out); 

     auto t = std::string(); 

     Read("temp.txt", t); 
    } 

    // Write and read back a set of ints. 

    { 
     auto const v1 = std::vector<int>() = { 10, 20, 30, 40, 50 }; 

     Write("temp.txt", v1, std::ios_base::trunc | std::ios_base::out | std::ios_base::binary); 

     auto v2 = std::vector<int>(); 

     Read("temp.txt", v2); 
    } 

    return 0; 
} 

傳遞一個迭代的容器,而不是使用「新」。

4

從C++文檔:http://cplusplus.com/reference/istream/istream/read

「此功能簡單的拷貝數據的塊,而不檢查其內容,也不在末端附加空字符」。

因此,您的字符串會錯過指示字符串結尾的結尾空字符。在這種情況下,cout將繼續在內存中打印超出thefile的字符。

在字符串末尾添加'\0'

+0

擴大您的答案,以包含更正的代碼,這是完美的。 –

+0

謝謝你,我發現它是最清楚的答案。我所做的只是將1加到緩衝區的大小,然後使最後一個索引='\ 0'。有更好的方法還是這樣好? – Matt

+0

@DanielJour:我留給讀者看,我認爲很清楚該怎麼做。 –