2013-08-28 17 views
0

指的這個問題:Efficient way of reading a file into an std::vector<char>? 我需要做的事情followig功能:將文件的一部分讀入std :: vector的有效方法<char>?

void readFromFile(std::vector< unsigned char >& buffer, 
        string filename, 
        size_t offset, size_t count); 

所以從偏移從文件中讀取的功能,以抵消+算入載體;

void readFromFile(std::vector< unsigned char >& buffer, 
        string filename, 
        size_t offset, size_t count) 
{ 
    // get file size and reallocate the buffer 
    size_t fsize = filesize(filename); 
    buffer.reserve(buffer.size() + size); 

    // open the file 
    ifstream file(filename); 

    // first way 
    file.seekg(offset); 
    file.read(????) 

    // second way 
    istreambuf_iterator< unsigned char > from(file); 
    istreambuf_iterator< unsigned char > eof; 

    advance(from, offset); 
    copy(from, eof, back_inserter(buffer); 
} 

在第一種方法中,我不知道如何一次讀取文件。在第二種方式中,讀操作很慢,因爲我每字節讀取一個字節。

是更好的選擇嗎?

編輯

由於@Ben福格特

我寫了這兩個簡單的功能:

inline std::streamsize filesize(const std::string& filename) 
{ 
    std::ifstream in(filename, std::ifstream::in | std::ifstream::binary); 
    if (!in) throw std::invalid_argument 
    { 
     "filesize error: invalid filename" 
    }; 

    in.seekg(0, std::ifstream::end); 
    return in.tellg(); 

    // here the file is closed. so no need to restore the get pointer 
} 

inline std::streamsize filesize(std::ifstream& file) 
{ 
    file.seekg(0, std::ifstream::end); 
    const auto size = file.tellg(); 
    file.seekg(0);  // restore the get pointer 
    return size; 
} 

template< typename RAIter > 
inline void read_file(std::istream& file, 
         RAIter first, RAIter last, 
         std::streamsize offset = 0 
         ) 
{ 
    const auto size = last - first; 
    file.seekg(offset, std::ifstream::beg); 
    file.read(reinterpret_cast< char* >(&*first), size); 
} 

template<> 
inline void read_file(std::istream& file, 
         unsigned char* first, unsigned char* last, 
         std::streamsize offset /*= 0 no default argument in template spacalization. */ 
     ) 
{ 
    const auto size = last - first; 
    file.seekg(offset, std::ifstream::beg); 
    file.read(reinterpret_cast< char* >(first), size); 
} 

所以函數現在變得容易:

vector< unsigned char > buffer; 
// do something with buffer 

const string filename{ "blabla" }; 

const auto size = filesize(filename); 

// resize the buffer 
auto const OLD_LEN = buffer.size(); 
buffer.resize(OLD_LEN + size); 

size_t startOffset = 0;  // from where to star reading from file 
size_t cont = size;   // how manny bytes read from file 

// read filename from startOffset to startOffset + count, appendeing in buffer 
ifstream file(filename); 
read_file(file, 
      buffer.data() + OLD_LEN, 
      buffer.data() + OLD_LEN + count, 
      startOffset 
      ); 
+0

你可以使用'reserve'和'back_inserter'和'std :: copy',或者'resize'來獲得一個有效的內存區域來直接填充。 –

+0

爲什麼不把'mmap()'數據放入你的虛擬地址空間?爲什麼你需要一個'矢量'? – cmaster

+0

@cdhowie我總是這樣做。也許電擊療法最終會打破我的這種習慣。 – WhozCraig

回答

3
auto old_end = buffer.size(); 
buffer.resize(old_end + blocksize); 

//... 

file.read(&buffer[old_end], blocksize); 
auto actual_size = file.gcount; 
if (actual_size < blocksize) buffer.resize(old_end + actual_size); 
+0

+1我完全錯過了他想將新塊添加到現有緩衝區。 (我並不完全確定他是這樣做的,但根據他在透氣性中所做的尺寸,它肯定是有意義的)。 – WhozCraig

+0

@WhozCraig:這並不清楚,但他確實擴大了「儲備」的規模,而不是取而代之。 –

+0

對於短篇閱讀也有不錯的觸動(即將提出這個建議)。 – WhozCraig

0

這裏有一個快速高效的獲取角色的方式來自文件的光線。

char * arr; 
int len; 
// Function that opens a file, needing the file name 
void openFile(const char* fileName) 
{ 
ifstream file(fileName, ios::in); 

if(!file.is_open()) return; 

file.seekg(0, file.end); 
    // Get the length of the file 
len = file.tellg(); 
file.seekg(0, file.beg); 

arr = new char[len]; 
file.read(arr, len); 

file.close(); 
} 

之後,你可以將字符數組推到一個向量。

+2

'char arr [];'不是一個有效的定義,然後你會在'arr = new char [len];'中出現類型不匹配,然後你就會泄漏。你是否試圖在那裏編寫C#/ Java? –

+0

arr = new char [len];是一個gcc擴展,不支持visual C++ – Neil

相關問題