バイナリファイルI/O
生のバイトを読み書きします
「バイナリファイルI/O」はCoddyKit上の無料C++ Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC++ Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C++ Academyコースには全4レッスンが含まれています。
テキストとバイナリ
テキストモードでは人間が読める文字を書き込みます。バイナリモードでは、オブジェクトがメモリ上にある状態のまま、生のバイトを書き込みます。std::ios::binaryを指定して開いてください。
#include <iostream>
#include <fstream>
int main() {
int value = 12345;
std::ofstream out("v.bin", std::ios::binary);
out.write(reinterpret_cast<const char*>(&value), sizeof(value));
std::cout << "wrote " << sizeof(value) << " bytes\n";
return 0;
}writeはバイトを受け取る
write(ptr, n)は、ptrから生のバイトをn個出力します。オブジェクトのアドレスをconst char*にキャストします。
#include <iostream>
#include <fstream>
int main() {
double d = 3.14;
std::ofstream out("d.bin", std::ios::binary);
out.write(reinterpret_cast<const char*>(&d), sizeof(d));
out.close();
std::cout << "saved a double\n";
return 0;
}readでバイトを復元する
read(ptr, n)は、ptrが指すオブジェクトにnバイトを読み込み、バイナリ書き込みを逆の操作で復元します。
#include <iostream>
#include <fstream>
int main() {
int original = 777;
std::ofstream("i.bin", std::ios::binary).write(reinterpret_cast<const char*>(&original), sizeof(original));
int loaded = 0;
std::ifstream in("i.bin", std::ios::binary);
in.read(reinterpret_cast<char*>(&loaded), sizeof(loaded));
std::cout << loaded << '\n';
return 0;
}POD構造体を書き込む
POD構造体(ポインターを持たず、メンバーが固定サイズの構造体)は、1つのバイトブロックとしてそのまま書き出し、読み戻せます。
#include <iostream>
#include <fstream>
struct Record { int id; double balance; };
int main() {
Record r{1, 99.5};
std::ofstream out("rec.bin", std::ios::binary);
out.write(reinterpret_cast<const char*>(&r), sizeof(r));
std::cout << "struct saved\n";
return 0;
}構造体を読み戻す
1回のread呼び出しで、構造体全体を復元できます。
#include <iostream>
#include <fstream>
struct Record { int id; double balance; };
int main() {
Record w{42, 250.0};
std::ofstream("r2.bin", std::ios::binary).write(reinterpret_cast<const char*>(&w), sizeof(w));
Record r{};
std::ifstream in("r2.bin", std::ios::binary);
in.read(reinterpret_cast<char*>(&r), sizeof(r));
std::cout << r.id << ' ' << r.balance << '\n';
return 0;
}配列を書き込む
配列の合計バイトサイズを渡すと、配列全体を1回の呼び出しで書き込めます。
#include <iostream>
#include <fstream>
int main() {
int arr[5] = {1, 2, 3, 4, 5};
std::ofstream out("arr.bin", std::ios::binary);
out.write(reinterpret_cast<const char*>(arr), sizeof(arr));
std::cout << "wrote " << sizeof(arr) << " bytes\n";
return 0;
}配列を読み戻す
同じサイズの配列に、同じバイト数を読み込みます。
#include <iostream>
#include <fstream>
int main() {
int src[5] = {10, 20, 30, 40, 50};
std::ofstream("a2.bin", std::ios::binary).write(reinterpret_cast<const char*>(src), sizeof(src));
int dst[5] = {};
std::ifstream in("a2.bin", std::ios::binary);
in.read(reinterpret_cast<char*>(dst), sizeof(dst));
for (int x : dst) std::cout << x << ' ';
std::cout << '\n';
return 0;
}位置を移動する
seekg(取得)とseekp(格納)を使うと、読み書き位置を移動でき、ファイル内にランダムアクセスできます。
#include <iostream>
#include <fstream>
int main() {
int data[3] = {100, 200, 300};
std::ofstream("seek.bin", std::ios::binary).write(reinterpret_cast<const char*>(data), sizeof(data));
std::ifstream in("seek.bin", std::ios::binary);
in.seekg(sizeof(int)); // skip to second int
int second; in.read(reinterpret_cast<char*>(&second), sizeof(second));
std::cout << second << '\n';
return 0;
}位置を取得する
tellgとtellpは現在位置を返します。ファイルサイズやオフセットの測定に便利です。
#include <iostream>
#include <fstream>
int main() {
int data[4] = {1, 2, 3, 4};
std::ofstream("tell.bin", std::ios::binary).write(reinterpret_cast<const char*>(data), sizeof(data));
std::ifstream in("tell.bin", std::ios::binary);
in.seekg(0, std::ios::end);
std::cout << "file size: " << in.tellg() << " bytes\n";
return 0;
}ポインターを使ってはいけない理由
ポインターやstd::stringを含むオブジェクトをバイナリ形式でそのまま書き出してはいけません。保存されるのはポインターが指すデータではなく、ポインターのアドレスだからです。代わりに内容をシリアライズしてください。
#include <iostream>
#include <fstream>
#include <string>
int main() {
std::string s = "hello";
std::ofstream out("str.bin", std::ios::binary);
std::size_t len = s.size();
out.write(reinterpret_cast<const char*>(&len), sizeof(len));
out.write(s.data(), len); // write the chars, not the object
std::cout << "serialized " << len << " chars\n";
return 0;
}移植性に関する注意
バイナリレイアウトはエンディアンや型のサイズに依存します。あるプラットフォームで書き込んだファイルは別のプラットフォームで正しく読み取れない場合があるため、共有する場合は固定フォーマットを定義してください。
#include <iostream>
#include <cstdint>
int main() {
std::int32_t fixed = 1; // fixed-width type for portability
std::cout << "sizeof int32_t = " << sizeof(fixed) << '\n';
return 0;
}クイックチェック
バイナリI/Oについて理解度を確認しましょう。
まとめ
バイナリファイルI/Oについて、次のことを学びました。
std::ios::binaryで開き、reinterpret_cast<char*>とwrite/readを使用しますseekg/seekpとtellg/tellpでランダムアクセスできます- ポインターや文字列を直接書き出さず、内容をシリアライズしてください。また、エンディアンにも注意が必要です
次は、ストリームの状態を確認し、エラーを処理する方法を学びます。
よくある質問
「バイナリファイルI/O」レッスンは無料ですか?
はい。「バイナリファイルI/O」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C++ Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C++ Academyコースには全4レッスンが含まれています。
「バイナリファイルI/O」で何を学びますか?
生のバイトを読み書きします ブラウザで直接実行するハンズオンコードでC++ Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
C++ Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのC++ Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「バイナリファイルI/O」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このC++ Academyレッスンでコードを書いて実行できますか?
はい。すべてのC++ Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。