C++でバイナリファイルに書き込む方法:writeメソッドの基本とサンプルコード
C++でバイナリファイルにデータを書き込むには、ofstreamクラスが提供するwriteメソッドを使用します。このメソッドは、「put」ポインタ(書き込み位置を示すポインタ)の現在位置から、指定したバイト数のデータをストリームに書き込むためのものです。
putポインタがファイルの末尾にある場合は、その位置からファイルが拡張され、新しいデータが追記されます。一方、ポインタがファイルの途中を指している場合は、既存の内容が新しいデータで上書きされる点に注意してください。
また、書き込み処理中に何らかのエラーが発生すると、ストリームは自動的にエラー状態に設定されます。そのため、書き込み後にはストリームの状態を必ずチェックする習慣をつけると安全です。
writeメソッドの構文
ostream& write(const char*, int);
第1引数には書き込むデータの先頭アドレス(char型ポインタ)、第2引数には書き込むバイト数を指定します。戻り値はストリーム自身への参照です。
処理の流れ(アルゴリズム)
1. 学生情報を保持する構造体 Student を定義する 2. バイナリモードでファイルを開く(書き込み用) 3. ファイルオープン時にエラーが発生していないか確認する 4. 構造体の変数にデータを設定する 5. ファイルが正常に開けていれば、writeメソッドでバイナリデータを書き込む 6. 書き込み用ファイルを閉じる 7. 書き込み時にエラーが発生していないか確認する 8. 保存したデータを出力する
サンプルコード
以下は、学生3人分のデータをバイナリファイル「student.dat」に書き込む例です。
#include<iostream>
#include<fstream>
using namespace std;
struct Student {
int roll_no;
string name;
};
int main() {
ofstream wf("student.dat", ios::out | ios::binary);
if(!wf) {
cout << "Cannot open file!" << endl;
return 1;
}
Student wstu[3];
wstu[0].roll_no = 1;
wstu[0].name = "Ram";
wstu[1].roll_no = 2;
wstu[1].name = "Shyam";
wstu[2].roll_no = 3;
wstu[2].name = "Madhu";
for(int i = 0; i < 3; i++)
wf.write((char *) &wstu[i], sizeof(Student));
wf.close();
if(!wf.good()) {
cout << "Error occurred at writing time!" << endl;
return 1;
}
cout << "Student's Details:" << endl;
for(int i = 0; i < 3; i++) {
cout << "Roll No: " << wstu[i].roll_no << endl;
cout << "Name: " << wstu[i].name << endl;
cout << endl;
}
return 0;
}実行結果
Student's Details: Roll No: 1 Name: Ram Roll No: 2 Name: Shyam Roll No: 3 Name: Madhu
実務上の注意点
サンプルでは構造体をそのままバイト列として書き出していますが、これは学習用のシンプルな例である点に留意してください。std::stringのような動的なメンバを持つクラスや構造体をそのままダンプすると、文字列本体ではなく内部ポインタが保存されるため、読み戻した際に正しく復元できず、未定義動作の原因にもなります。
実際の開発では、以下のいずれかの方法を検討するのが安全です。
- 可変長データは使わず、固定長のchar配列でメンバを定義する
- 各フィールドを個別にwrite/readで読み書きする
- JSONやProtocol Buffersなど、専用のシリアライズ機構を利用する
また、環境によってint型のサイズやエンディアンが異なるため、異なるプラットフォーム間でバイナリファイルをやり取りする場合は互換性にも注意が必要です。
-
C++で二分木を剪定する:1を含まない部分木を削除する再帰アルゴリズム
問題概要二分木のルートノード root が与えられ、すべてのノードの値は 0 または 1 のいずれかであるとします。この木から、1 を含まないすべての部分木を削除した結果の木を求めるのが目的です。たとえば、次のような木が与えられた場合 −解決のためのアプローチこの問題は、再帰的な手法を用いて以下の手順で解決できます −ノードを引数として受け取る再帰メソッド solve() を定義します。処理の流れは次のとおりです −ノードが null の場合は、null を返しますノードの左の子に対して solve(左の子) を実行し、その結果を左の子に代入しますノードの右の子に対して solve(右の子)
-
C++プログラムにおける二分探索(バイナリサーチ)の基本と実装
二分探索(バイナリサーチ)とは二分探索は「半区間探索」「対数探索」「バイナリチョップ」とも呼ばれる検索アルゴリズムで、ソート済みの配列の中から目的の値が存在する位置を効率的に見つけ出します。基本的な仕組みは非常にシンプルです。まず、探したい値(ターゲット値)を配列の中央の要素と比較します。一致しなかった場合は、ターゲット値が存在し得ない半分を丸ごと排除し、残りの半分に対して同様の比較を繰り返します。この「中央との比較」と「範囲の絞り込み」を続け、ターゲット値が見つかるか、検索範囲が空になる(=配列にその値が存在しない)かのどちらかで処理が終了します。アイデア自体は簡単ですが、正しく実装するには