Perlなどのスクリプト言語では、ファイルを一度に変数に読み込むことができます。
open(FILEHANDLE,$file);
$content=<FILEHANDLE>;
C++でこれを行う最も効率的な方法は何ですか?
このような:
#include <fstream>
#include <string>
int main(int argc, char** argv)
{
std::ifstream ifs("myfile.txt");
std::string content( (std::istreambuf_iterator<char>(ifs) ),
(std::istreambuf_iterator<char>() ) );
return 0;
}
声明
std::string content( (std::istreambuf_iterator<char>(ifs) ),
(std::istreambuf_iterator<char>() ) );
に分割することができます
std::string content;
content.assign( (std::istreambuf_iterator<char>(ifs) ),
(std::istreambuf_iterator<char>() ) );
既存のstd :: string変数の値を単に上書きしたい場合に便利です。
最も効率的ですが、C++ではありません。
FILE* f = fopen(filename, "r");
// Determine file size
fseek(f, 0, SEEK_END);
size_t size = ftell(f);
char* where = new char[size];
rewind(f);
fread(where, sizeof(char), size, f);
delete[] where;
#
EDIT-2std::filebuf
バリアントもテストしました。 C++のアプローチではなく、むしろラッパーであるにもかかわらず、最高のC++アプローチと呼ぶことができるようです。とにかく、ここに、普通のCとほぼ同じ速度で動作するコードの塊があります。
std::ifstream file(filename, std::ios::binary);
std::streambuf* raw_buffer = file.rdbuf();
char* block = new char[size];
raw_buffer->sgetn(block, size);
delete[] block;
ここで簡単なベンチマークを行いましたが、結果は次のとおりです。テストは、適切な(std::ios:binary
およびrb
)モードで65536Kバイナリファイルを読み取ることで行われました。
[==========] Running 3 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 4 tests from IO
[ RUN ] IO.C_Kotti
[ OK ] IO.C_Kotti (78 ms)
[ RUN ] IO.CPP_Nikko
[ OK ] IO.CPP_Nikko (106 ms)
[ RUN ] IO.CPP_Beckmann
[ OK ] IO.CPP_Beckmann (1891 ms)
[ RUN ] IO.CPP_Neil
[ OK ] IO.CPP_Neil (234 ms)
[----------] 4 tests from IO (2309 ms total)
[----------] Global test environment tear-down
[==========] 4 tests from 1 test case ran. (2309 ms total)
[ PASSED ] 4 tests.
最も効率的なのは、正しいサイズのバッファーを作成してから、ファイルをバッファーに読み込むことです。
#include <fstream>
#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.
* Because char is a POD data type it is not initialized.
*
* Then read the whole file into the buffer.
*/
std::vector<char> buffer(length);
file.read(&buffer[0],length);
}
}
テキストファイルに\0
が存在しないようにする必要があります。
#include<iostream>
#include<fstream>
using namespace std;
int main(){
fstream f(FILENAME, fstream::in );
string s;
getline( f, s, '\0');
cout << s << endl;
f.close();
}
これは、ファイルのサイズ、種類(テキスト/バイナリ)など、多くのことに依存します。先ほど、streambufイテレータを使用したバージョンに対して次の関数のベンチマークを行いました。
unsigned int FileRead( std::istream & is, std::vector <char> & buff ) {
is.read( &buff[0], buff.size() );
return is.gcount();
}
void FileRead( std::ifstream & ifs, string & s ) {
const unsigned int BUFSIZE = 64 * 1024; // reasoable sized buffer
std::vector <char> buffer( BUFSIZE );
while( unsigned int n = FileRead( ifs, buffer ) ) {
s.append( &buffer[0], n );
}
}
おそらく最も効率的ではありませんが、1行でデータを読み取ります。
#include<iostream>
#include<vector>
#include<iterator>
main(int argc,char *argv[]){
// read standard input into vector:
std::vector<char>v(std::istream_iterator<char>(std::cin),
std::istream_iterator<char>());
std::cout << "read " << v.size() << "chars\n";
}
反復子ベースのメソッドを次に示します。
ifstream file("file", ios::binary);
string fileStr;
istreambuf_iterator<char> inputIt(file), emptyInputIt
back_insert_iterator<string> stringInsert(fileStr);
copy(inputIt, emptyInputIt, stringInsert);