ファイルの内容を isstringstream に読み取るにはどうすればよいですか?
-
02-07-2019 - |
質問
ファイルからの読み取りパフォーマンスを向上させるために、大きな (数 MB) ファイルの内容全体をメモリに読み取り、istringstream を使用して情報にアクセスしようとしています。
私の質問は、この情報を読み取り、文字列ストリームに「インポート」する最良の方法はどれですか?このアプローチの問題点は (以下を参照)、文字列ストリームの作成時にバッファがコピーされ、メモリ使用量が 2 倍になることです。
#include <fstream>
#include <sstream>
using namespace std;
int main() {
ifstream is;
is.open (sFilename.c_str(), ios::binary );
// get length of file:
is.seekg (0, std::ios::end);
long length = is.tellg();
is.seekg (0, std::ios::beg);
// allocate memory:
char *buffer = new char [length];
// read data as a block:
is.read (buffer,length);
// create string stream of memory contents
// NOTE: this ends up copying the buffer!!!
istringstream iss( string( buffer ) );
// delete temporary buffer
delete [] buffer;
// close filestream
is.close();
/* ==================================
* Use iss to access data
*/
}
解決
std::ifstream
方法があります rdbuf()
, へのポインタを返します。 filebuf
. 。これを「プッシュ」できます filebuf
あなたの中に stringstream
:
#include <fstream>
#include <sstream>
int main()
{
std::ifstream file( "myFile" );
if ( file )
{
std::stringstream buffer;
buffer << file.rdbuf();
file.close();
// operations on the buffer...
}
}
編集:Martin York 氏がコメントで述べているように、これは、 stringstream
さんの operator<<
filebuf を 1 文字ずつ読み取ります。彼の答えをチェックしてみてください。どこで彼は ifstream
さんの read
これまでと同様にメソッドを選択し、 stringstream
以前に割り当てられたメモリを指すバッファ。
他のヒント
わかりました。ファイルから読み取るよりも速いとは言っていません。
ただし、これはバッファを一度作成し、データがバッファに読み込まれた後、それを stringstream のソースとして直接使用する方法です。
注:std::ifstream はバッファリングされることに注意してください。ファイルからデータを (比較的大きな) チャンクに分けて読み取ります。ストリーム操作は、さらにデータが必要な場合にのみ、別の読み取りのためにファイルに戻るバッファに対して実行されます。したがって、すべてのデータをメモリに吸い込む前に、これがボトルネックであることを確認してください。
#include <fstream>
#include <sstream>
#include <vector>
int main()
{
std::ifstream file("Plop");
if (file)
{
/*
* Get the size of the file
*/
file.seekg(0,std::ios::end);
std::streampos length = file.tellg();
file.seekg(0,std::ios::beg);
/*
* Use a vector as the buffer.
* It is exception safe and will be tidied up correctly.
* This constructor creates a buffer of the correct length.
*
* Then read the whole file into the buffer.
*/
std::vector<char> buffer(length);
file.read(&buffer[0],length);
/*
* Create your string stream.
* Get the stringbuffer from the stream and set the vector as it source.
*/
std::stringstream localStream;
localStream.rdbuf()->pubsetbuf(&buffer[0],length);
/*
* Note the buffer is NOT copied, if it goes out of scope
* the stream will be reading from released memory.
*/
}
}
これは時期尚早な最適化のように思えます。処理中にどれだけの作業が行われているか。組み込みシステムではなく、最新のデスクトップ/サーバーを想定すると、初期化中に数 MB のデータをコピーするのは、特に最初にディスクからファイルを読み取る場合と比較すると、かなり安価です。私なら、あなたが持っているものを使い続け、完成したらシステムを測定し、潜在的なパフォーマンスの向上がそれだけの価値があるかどうかを判断します。もちろん、メモリが不足している場合は、これが内部ループ内にあるか、頻繁に (1 秒に 1 回など) 呼び出されるプログラム内にあるため、バランスが変化します。
もう 1 つ留意すべき点は、ファイル I/O は常に最も遅い操作になるということです。Luc Touraille の解決策は正しいですが、他の選択肢もあります。ファイル全体を一度にメモリに読み取ると、個別に読み取るよりもはるかに高速になります。