はじめに
C++でファイルの内容を全て vector
や string
に読み込みたい場合、while
ループで1文字または1行ずつ読み込んでいくのが基本的な方法です。しかし、この方法はコードが冗長になりがちです。
よりモダンで簡潔なアプローチが、std::istreambuf_iterator
を使う方法です。これは、入力ストリーム(ファイルなど)のバッファを直接読み取る特殊なイテレータです。コンテナの範囲コンストラクタと組み合わせることで、ファイルの内容全体を、たった一行でコンテナに流し込むことができます。
ファイル全体を一度に読み込むサンプルコード
このコードは、まずテスト用のファイル data.bin
を作成し、その後 std::ifstream
と std::istreambuf_iterator
を使って、そのファイルの内容を vector<char>
に一括で読み込みます。
完成コード
#include <iostream>
#include <fstream> // ifstream, ofstream
#include <vector>
#include <iterator> // istreambuf_iterator
#include <string>
using namespace std;
int main() {
const string filename = "data.bin";
// 1. テスト用のファイルを作成
ofstream ofs(filename, ios_base::binary);
ofs << "Hello, C++!";
ofs.close();
// 2. ファイルをバイナリモードで開く
ifstream ifs(filename, ios_base::binary);
// ファイルが開けなかった場合のエラーチェック
if (!ifs) {
cerr << "ファイルを開けません: " << filename << endl;
return 1;
}
// 3. istreambuf_iteratorを使って、ファイル全体をvectorに一括で読み込む
vector<char> file_contents(
(istreambuf_iterator<char>(ifs)), // 開始イテレータ
(istreambuf_iterator<char>()) // デフォルトコンストラクタで終了イテレータ
);
// 4. 読み込んだ内容を確認
cout << "ファイルから読み込んだ内容 (" << file_contents.size() << "バイト):" << endl;
for (char c : file_contents) {
cout << c;
}
cout << endl;
return 0;
}
コードの解説
vector<char> file_contents( (istreambuf_iterator<char>(ifs)), (istreambuf_iterator<char>()) );
これが、ファイル全体を読み込む核心部分であり、「イテレータペアコンストラクタ」と呼ばれる vector
のコンストラクタを利用しています。
vector<char> file_contents(...)
:vector
のコンストラクタは、開始イテレータと終了イテレータを引数として受け取り、その範囲の要素でvector
を初期化できます。istreambuf_iterator<char>(ifs)
: これが開始イテレータです。ifstream
オブジェクトifs
を引数としてコンストラクタを呼び出すと、そのファイルの先頭を指すistreambuf_iterator
が生成されます。istreambuf_iterator<char>()
: こちらが終了イテレータです。istreambuf_iterator
は、引数なしのデフォルトコンストラクタで生成すると、ストリームの終端を表す特別なイテレータになります。
vector
のコンストラクタは、開始イテレータから始まり、終了イテレータに到達するまで、ストリームから文字を一つずつ読み込んで vector
に追加していきます。istreambuf_iterator
はバッファを直接読むため、非常に高速に動作します。
まとめ
今回は、C++の std::istreambuf_iterator
を使って、ファイルの内容をコンテナに一括で、かつ効率的に読み込む方法を解説しました。
std::istreambuf_iterator
は、入力ストリームのバッファを直接読む高速なイテレータ。vector
などの範囲コンストラクタと組み合わせることで、ファイル全体を一行で読み込める。コンテナ変数( (istreambuf_iterator<char>(ifs)), (istreambuf_iterator<char>()) )
このイディオム(定石)は、バイナリファイルやテキストファイルをまとめてメモリに読み込んでから処理したい場合に、非常に強力で簡潔な方法です。