C++: ファイル操作応用
最終更新:2026-08-31
レッスン40では、例外処理について学びました。
ここでは、ファイルについて学びます——プログラマの必須スキルです。
ファイル、データベース、設定ファイルなど、ファイル操作は不可欠です。
1. ファイルストリーム
(1) 1.1 ファイルストリームクラス
C++はクラスでファイルを操作します:
| クラス | 機能 |
|---|---|
std::ifstream |
入力ファイルストリーム(読み取り) |
std::ofstream |
出力ファイルストリーム(書き込み) |
std::fstream |
入出力ファイルストリーム(読み書き) |
(2) 1.2 ファイルを開く
▶ サンプル 2:ファイルを開く(難易度 ⭐)
TEXT
📖 参照専用
#include <iostream>
#include <fstream>
int main() {
std::ifstream file("data.txt");
if (!file) {
std::cerr << "ファイルを開けません" << std::endl;
return 1;
}
std::cout << "ファイルを開きました" << std::endl;
file.close();
return 0;
}
2. ファイルの読み書き
(1) 2.1 行単位で読む
▶ サンプル:ファイルを開く(難易度 ⭐)
CPP
#include <iostream>
#include <fstream>
#include <string>
int main() {
std::ifstream file("data.txt");
std::string line;
int count = 0;
while (std::getline(file, line)) {
count++;
}
std::cout << "行数:" << count << std::endl;
file.close();
return 0;
}
(2) 2.2 書式付き入出力
▶ サンプル:構造体の書き込み(難易度 ⭐⭐)
CPP
#include <iostream>
#include <fstream>
struct Student {
char name[50];
int age;
double score;
};
int main() {
Student s = {"田中太郎", 20, 85.5};
// 書き込み
std::ofstream out("student.txt");
out << s.name << std::endl;
out << s.age << std::endl;
out << s.score << std::endl;
out.close();
// 読み取り
Student s2;
std::ifstream in("student.txt");
in >> s2.name >> s2.age >> s2.score;
in.close();
std::cout << "名前:" << s2.name << std::endl;
std::cout << "年齢:" << s2.age << std::endl;
std::cout << "スコア:" << s2.score << std::endl;
return 0;
}
⚠️ 注意:
- 書式付き入力は空白で区切られるため、注意が必要(
>>演算子の仕様)
3. バイナリファイル
(1) 3.1 なぜバイナリファイル?
| 特徴 | テキストファイル | バイナリファイル |
|---|---|---|
| 可読性 | 人間が読める | 機械向け |
| サイズ | 大きい | 小さい |
| 精度 | 変換で精度損失 | 精度維持 |
| 移植性 | 高い | (エンディアン問題あり) |
(2) 3.2 バイナリ書き込み
▶ サンプル:構造体のバイナリ書き込み(難易度 ⭐⭐⭐)
CPP
#include <iostream>
#include <fstream>
struct Student {
char name[50];
int age;
double score;
};
int main() {
Student s = {"田中太郎", 20, 85.5};
// バイナリ書き込み
std::ofstream out("student.bin", std::ios::binary);
out.write(reinterpret_cast<char*>(&s), sizeof(s));
out.close();
// バイナリ読み取り
Student s2;
std::ifstream in("student.bin", std::ios::binary);
in.read(reinterpret_cast<char*>(&s2), sizeof(s2));
in.close();
std::cout << "名前:" << s2.name << std::endl;
std::cout << "年齢:" << s2.age << std::endl;
std::cout << "スコア:" << s2.score << std::endl;
return 0;
}
💡 ヒント:
- バイナリ入出力には
writeとreadを使用 - データサイズを正確に管理(
sizeof)
4. 4. ランダムアクセス
(1) 4.1 seekgとseekp
ファイルの読み取り位置と書き込み位置を移動します。
| 関数 | 機能 |
|---|---|
seekg(pos) |
読み取り位置を設定 |
seekp(pos) |
書き込み位置を設定 |
tellg() |
現在の読み取り位置を取得 |
tellp() |
現在の書き込み位置を取得 |
(2) 4.2 例:ファイルの特定位置を変更(難易度 ⭐⭐⭐)
CPP
#include <iostream>
#include <fstream>
int main() {
std::fstream file("data.txt", std::ios::in | std::ios::out);
// 10バイト目に移動
file.seekp(10);
// そこに書き込み(上書き)
file << "Hello";
file.close();
return 0;
}
5. ファイルストリームの状態
(1) 5.1 状態関数
ファイルストリームには4つの状態関数があります:
| 関数 | 説明 |
|---|---|
good() |
正常 |
eof() |
ファイル終端に到達 |
fail() |
エラー(型不一致など) |
bad() |
重大なエラー(ストリーム破損) |
(2) 5.2 状態の確認
▶ サンプル:ファイル終端の検出(難易度 ⭐)
CPP
#include <iostream>
#include <fstream>
int main() {
std::ifstream file("data.txt");
std::string line;
while (true) {
std::getline(file, line);
if (file.eof()) {
break; // 終端に到達
}
std::cout << line << std::endl;
}
file.clear(); // 状態をクリア
file.close();
return 0;
}
6. 実践:簡易データベース
▶ サンプル 1:学生記録管理(難易度 ⭐⭐⭐)
TEXT
📖 参照専用
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
struct Student {
int id;
char name[50];
int age;
};
void saveStudents(const std::vector<Student>& students, const std::string& filename) {
std::ofstream file(filename, std::ios::binary);
for (const auto& s : students) {
file.write(reinterpret_cast<const char*>(&s), sizeof(s));
}
}
void loadStudents(std::vector<Student>& students, const std::string& filename) {
std::ifstream file(filename, std::ios::binary);
Student s;
while (file.read(reinterpret_cast<char*>(&s), sizeof(s))) {
students.push_back(s);
}
}
int main() {
std::vector<Student> students = {
{1, "田中太郎", 20},
{2, "佐藤花子", 21}
};
// 保存
saveStudents(students, "students.bin");
// 読み取り
std::vector<Student> loaded;
loadStudents(loaded, "students.bin");
std::cout << "読み取り完了:" << loaded.size() << "件のデータ" << std::endl;
return 0;
}
▶ サンプル 3:ファイルへの追記(難易度 ⭐⭐)
CPP
#include <iostream>
#include <fstream>
#include <string>
int main() {
// 追記モードでファイルを開く
std::ofstream outFile("log.txt", std::ios::app);
if (!outFile) {
std::cerr << "追記用にファイルを開けません" << std::endl;
return 1;
}
// 複数行を追記
outFile << "ログエントリ 1: プログラム開始" << std::endl;
outFile << "ログエントリ 2: データ処理中" << std::endl;
outFile << "ログエントリ 3: プログラム終了" << std::endl;
outFile.close();
// ファイル全体を読む
std::ifstream inFile("log.txt");
std::string line;
std::cout << "ファイル内容:" << std::endl;
while (std::getline(inFile, line)) {
std::cout << line << std::endl;
}
inFile.close();
return 0;
}
出力:
TEXT 📖 参照専用ファイル内容: ログエントリ 1: プログラム開始 ログエントリ 2: データ処理中 ログエントリ 3: プログラム終了
❓ よくある質問
Q:テキストファイルとバイナリファイルの使い分けは? A: 可読性が必要 → テキストファイル - パフォーマンス/サイズ優先 → バイナリファイル - 移植性優先 → テキストファイル
Q:文字コードは? A: C++標準は文字コードを規定しません。対策:- UTF-8でファイルを保存 - 変換ライブラリを使用(iconvなど) - プラットフォーム固有のAPIを使用
Q:ファイルオープン失敗の対処は? A:
if (!file)でチェック、例外処理で対処。
📖 まとめ
| トピック | 要点 |
|---|---|
| ファイルストリームクラス | ifstream/ofstream/fstream |
| テキストファイル | << と >> で入出力 |
| バイナリファイル | write と read で入出力 |
| ランダムアクセス | seekg/seekp で位置移動 |
| 状態確認 | eof()/fail()/bad() |
📝 練習問題
-
初級(難易度 ⭐):
ofstreamでファイルに「Hello World」を書き込み、ifstreamで読み込んで出力してください。 -
中級(難易度 ⭐⭐):
fstreamとios::binaryでバイナリファイルを扱い、構造体配列を書き込み、読み込んでください。 -
上級(難易度 ⭐⭐⭐):
seekg/tellgでファイルサイズを取得する機能を実装してください。「ファイルブラウザ」のような機能を作り、ファイルの特定位置からデータを読み込んでください。
- ファイルストリーム:ifstream(読み取り)/ ofstream(書き込み)/ fstream(読み書き)
- オープンモード:in/out/app/binary/trunc
- 状態確認:is_open/good/fail/eof
- テキストファイル vs バイナリファイル:可読性と効率のトレードオフ
- ランダムアクセス:seekg/tellg で読み取り位置、seekp/tellp で書き込み位置
次のレッスン:正規表現(#42)