C++で使えるバイナリファイルの読み書き9選

C++でのバイナリファイル操作を解説するイメージC++
この記事は約17分で読めます。

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

C++によるバイナリファイルの読み書きは、プログラミングの世界で非常に重要なスキルの一つです。

この記事では、初心者から上級者までがC++を使ってバイナリファイルを効率的に操作するための方法を、実用的なサンプルコードと共に詳細に解説します。

この記事を通じて、あなたはファイルの基本的な読み書きから、より高度な操作まで、C++で行うことができるようになるでしょう。

●C++とバイナリファイルの基本

C++は、高性能が要求されるアプリケーション開発に広く使用されるプログラミング言語です。

その特性上、バイナリファイルの読み書きはC++プログラミングにおいて避けて通れないトピックの一つとなります。

バイナリファイルは、テキストファイルとは異なり、人間が直接読むことは難しいが、コンピュータにとっては高速に処理できるデータ形式です。

○C++におけるバイナリファイルの重要性

バイナリファイルは、そのコンパクトさと効率性から、大量のデータを扱うアプリケーションや、システムレベルのプログラミングにおいて広く利用されています。

C++でバイナリファイルを操作する能力を身につけることは、リソースの制限された環境や、パフォーマンスが重要視されるシナリオにおいて特に価値があります。

○バイナリファイルとは何か

バイナリファイルとは、テキストではなくバイナリデータとして格納されているファイルのことを指します。

これには、画像、音声、ビデオファイルなど、多岐にわたる形式が含まれます。

C++においてバイナリファイルを操作することは、これらのファイル形式を効率的に扱うために不可欠な技術です。

●C++でバイナリファイルを読む方法

C++を用いてバイナリファイルを読むための方法を詳しく解説しましょう。

バイナリファイルの読み込みは、プログラミングにおいて非常に重要なスキルです。

C++には、この目的のために特別に設計された機能がいくつかあります。

まず、必要なヘッダーファイルをインクルードすることから始めます。主に、ヘッダーが使用されます。

これにより、ファイル入出力に関する標準的なクラスや関数が利用可能になります。

次に、ファイルストリームオブジェクトを作成し、必要に応じてバイナリモードでファイルを開きます。

C++では、ifstream(入力ファイルストリーム)クラスを使用して、ファイルからデータを読み込みます。

特にバイナリファイルの場合は、ifstreamオブジェクトを作成する際に、ios::binaryフラグを指定してファイルをバイナリモードで開きます。

これにより、ファイルから読み込まれるデータはバイナリ形式として扱われます。

ファイルからのデータ読み込みは、特定のデータ型に合わせて行われます。

○サンプルコード1:基本的なバイナリファイルの読み込み

ここでは、C++でバイナリファイルを開き、内容を読み込む基本的なプロセスを紹介します。

この例では、バイナリモードでファイルを開き、ファイルの内容をバイト単位で読み込みます。

#include <iostream>
#include <fstream>
#include <vector>

int main() {
    std::ifstream file("example.bin", std::ios::binary);
    if (!file) {
        std::cerr << "ファイルを開けませんでした。" << std::endl;
        return 1;
    }

    std::vector<char> buffer(std::istreambuf_iterator<char>(file), {});
    for (char c : buffer) {
        std::cout << c;
    }

    return 0;
}

このコードは、”example.bin”という名前のファイルをバイナリモードで開き、その内容をstd::vectorに読み込んで表示します。

ifstreamオブジェクトがファイルを正しく開いているかどうかを確認し、その後ファイルの内容を読み込む処理を行います。

○サンプルコード2:バイナリデータの解析

次に、バイナリファイルから特定のデータ型のデータを読み込む方法を見ていきます。

この例では、ファイルから整数値を読み込む方法を紹介します。

#include <iostream>
#include <fstream>

int main() {
    std::ifstream file("example.bin", std::ios::binary);
    if (!file) {
        std::cerr << "ファイルを開けませんでした。" << std::endl;
        return 1;
    }

    int number;
    file.read(reinterpret_cast<char*>(&number), sizeof(number));
    std::cout << "読み込んだ数値: " << number << std::endl;

    return 0;
}

ここでは、整数データをバイナリファイルから直接読み込む方法を表しています。

file.read関数を使用して、指定されたバイト数分のデータを読み込みます。

reinterpret_castを使用して、整数変数のアドレスをchar型のポインタに変換しています。

これにより、バイナリファイルから直接整数値を読み込むことが可能になります。

●C++でバイナリファイルを書く方法

C++を使用してバイナリファイルにデータを書き込む方法について詳しく解説します。

C++では、ライブラリのofstreamクラスを利用してバイナリファイルに書き込みを行います。

バイナリファイルへの書き込みは、テキストファイルとは異なり、データをバイナリ形式で直接ファイルに書き出します。

これにより、データの構造をそのまま維持しつつ、効率的にデータを保存することができます。

ファイルを開く際には、ios::binaryフラグを使用してバイナリモードで開きます。

これにより、ファイルへの書き込みがバイナリ形式で行われるようになります。

○サンプルコード3:基本的なバイナリファイルの書き込み

基本的なバイナリファイルへの書き込み方法を表すサンプルコードを紹介します。

この例では、整数データをバイナリファイルに書き込みます。

#include <iostream>
#include <fstream>

int main() {
    std::ofstream file("example.bin", std::ios::binary);
    if (!file) {
        std::cerr << "ファイルを開けませんでした。" << std::endl;
        return 1;
    }

    int number = 123;
    file.write(reinterpret_cast<const char*>(&number), sizeof(number));

    return 0;
}

このコードでは、”example.bin”という名前のファイルをバイナリモードで開き、整数値を書き込んでいます。

write関数を用いて整数データをバイナリ形式でファイルに書き込む際には、データのアドレスをchar型のポインタに変換する必要があります。

○サンプルコード4:複雑なデータ構造の書き込み

複雑なデータ構造をバイナリファイルに書き込む例を紹介します。

この例では、構造体を含むデータをファイルに書き込みます。

#include <iostream>
#include <fstream>

struct MyData {
    int id;
    double value;
};

int main() {
    std::ofstream file("example.bin", std::ios::binary);
    if (!file) {
        std::cerr << "ファイルを開けませんでした。" << std::endl;
        return 1;
    }

    MyData data = {1, 3.14};
    file.write(reinterpret_cast<const char*>(&data), sizeof(data));

    return 0;
}

このコードでは、MyData構造体のインスタンスを作成し、そのデータをバイナリファイルに書き込んでいます。

複数の異なる型のデータを含む複雑な構造体も、バイナリ形式で効率的に保存できることがこの例からわかります。

バイナリファイルへの書き込みでは、構造体のメモリレイアウトがそのままファイルに反映されます。

●バイナリファイルの読み書きにおけるエラー処理

バイナリファイルの読み書きプロセスにおいて、エラー処理は非常に重要な要素です。

C++では、エラーが発生した際に適切な対応を行うための機能が提供されています。

ファイル操作においてエラーが発生する可能性のある状況としては、ファイルが見つからない、アクセス権限がない、ディスクスペースが不足しているなどがあります。

これらのエラーに対応するためには、ファイル操作を行う際にエラーが発生したかどうかをチェックし、発生した場合は適切なエラーメッセージを表示したり、代替の処理を行うなどの対応が必要です。

エラー処理の基本的なアプローチには、例外処理を使用する方法と、エラーチェックを行う方法の2種類があります。

例外処理を用いる方法では、ファイル操作時に何らかの問題が発生した場合に例外がスローされ、それをcatch節で捕捉して処理します。

一方、エラーチェックを行う方法では、ファイル操作の後にファイルストリームの状態を確認し、エラーが発生していた場合には適切な処理を行います。

○サンプルコード5:エラーハンドリングの実装

ここでは、エラーハンドリングを行う具体的なサンプルコードを紹介します。

この例では、ファイルを開く際にエラーが発生した場合に、エラーメッセージを表示してプログラムを終了させる処理を行っています。

#include <iostream>
#include <fstream>

int main() {
    std::ifstream file("example.bin", std::ios::binary);
    if (!file) {
        std::cerr << "ファイルを開けませんでした。エラー: " << strerror(errno) << std::endl;
        return 1;
    }

    // ファイル操作の処理

    file.close();
    return 0;
}

このコードでは、ifstreamオブジェクトを用いてファイルを開いています。

ファイルが正常に開けなかった場合(!fileが真の場合)、エラーメッセージを標準エラー出力に表示し、プログラムを終了します。

エラーメッセージにはstrerror関数を用いてerrnoのエラー内容を文字列で取得し、それを表示しています。

これにより、ファイルを開く際に発生する可能性のあるエラーに対応できます。

●バイナリファイル操作の応用例

C++でのバイナリファイル操作は多岐にわたり、データ保存やデータの圧縮・解凍など、様々な応用が可能です。

これらの応用例は、プログラムが扱うデータの量を減らすことに役立ち、またデータを安全に保存する際にも重要な役割を果たします。

バイナリファイルを使用する主な利点は、テキスト形式に比べてデータがコンパクトになり、読み書きのパフォーマンスが向上することです。

特に、大量のデータを扱うアプリケーションや、パフォーマンスが重要な場面では、バイナリファイルの使用が有効です。

データの圧縮と解凍は、特に大きなファイルを扱う場合や、ネットワークを介してデータを送受信する場合に有用です。

圧縮によってファイルサイズを削減し、ストレージの効率を高めることができます。また、解凍によって圧縮されたデータを元の状態に戻すことができます。

○サンプルコード6:バイナリファイルを使ったデータ保存

バイナリファイルを用いたデータ保存の例を紹介します。

ここでは、複数のデータをバイナリ形式でファイルに書き込むプロセスを説明します。

#include <iostream>
#include <fstream>
#include <vector>

int main() {
    std::vector<int> data = {1, 2, 3, 4, 5};
    std::ofstream file("data.bin", std::ios::binary);

    if (!file) {
        std::cerr << "ファイルを開けませんでした。" << std::endl;
        return 1;
    }

    for (int i : data) {
        file.write(reinterpret_cast<char*>(&i), sizeof(i));
    }

    file.close();
    return 0;
}

このコードは、整数のベクトルを作成し、それをバイナリファイルに書き込んでいます。

各整数はバイナリ形式でファイルに保存されます。

○サンプルコード7:バイナリファイルを使ったデータの圧縮と解凍

次に、データの圧縮と解凍の例を見てみましょう。

このプロセスでは、外部の圧縮ライブラリを使用して、バイナリデータの圧縮と解凍を行います。

// 外部ライブラリを用いた圧縮・解凍の例です。
// 実際のコードでは、適切な圧縮ライブラリを選択し、ライブラリのAPIに従って圧縮・解凍処理を実装します。

// 例: データを圧縮する
void compressData(std::vector<char>& data) {
    // 圧縮処理
}

// 例: データを解凍する
void decompressData(std::vector<char>& compressedData) {
    // 解凍処理
}

この例では、具体的な圧縮・解凍の処理は省略していますが、実際には外部ライブラリのAPIを使用してこれらの処理を実装します。

適切な圧縮アルゴリズムを選択し、データを効率的に圧縮・解凍することで、ストレージの節約やデータ転送の効率化が図れます。

●C++でのバイナリファイル操作の注意点

C++を使用してバイナリファイルを操作する際には、いくつかの重要な注意点があります。

後述する注意点を理解し、適切に対処することで、バイナリファイルの読み書きを効率的かつ安全に行うことができます。

○データ構造の一貫性

バイナリファイルにデータを書き込む際は、特にデータ構造が一貫していることを確認する必要があります。

例えば、特定のクラスや構造体を使用してデータをファイルに保存する場合、同じクラスや構造体を使ってデータを読み込むことで、データの整合性を保つことができます。

○ファイルの読み書き時の安全性

ファイルの読み書き操作を行う際には、ファイルの存在確認やエラーチェックを徹底することが重要です。

ファイルが存在しない場合の処理や、読み書き権限がない場合の対応、ファイル操作中に発生したエラーへの対応など、安全なファイル操作を確保するための措置を講じる必要があります。

●バイナリファイルのカスタマイズ方法

バイナリファイルを扱う際、特定のニーズに合わせてファイル形式をカスタマイズすることがあります。

カスタムバイナリファイルは、特定のアプリケーションやシステムに特化しており、標準的なファイル形式では対応できない特殊な要件を満たすために使用されます。

カスタムフォーマットを作成する際には、データの整理、アクセスの速度、そしてファイルの構造を考慮する必要があります。

カスタムバイナリファイルを作成する場合、そのファイルの構造やデータタイプについての明確な理解が不可欠です。

これにより、ファイルの読み込みや書き込み、データの処理が効率的に行えるようになります。

○サンプルコード8:カスタムバイナリフォーマットの作成

ここでは、特定のデータ構造を持つカスタムバイナリファイルを作成する例を紹介します。

#include <iostream>
#include <fstream>

struct MyData {
    int id;
    double value;
    char name[10];
};

int main() {
    MyData data = {1, 3.14, "Sample"};
    std::ofstream file("custom.bin", std::ios::binary);

    if (!file) {
        std::cerr << "ファイルを開けませんでした。" << std::endl;
        return 1;
    }

    file.write(reinterpret_cast<char*>(&data), sizeof(data));
    file.close();

    return 0;
}

このコードでは、MyData 構造体を定義し、それを使用してバイナリファイルに書き込んでいます。

このようなカスタムフォーマットは、アプリケーションに特化したデータ保存や、特定のデータ構造に対応するために役立ちます。

○サンプルコード9:カスタムバイナリファイルのパース

カスタムバイナリファイルを使用する場合、ファイルからデータを読み出し、解析(パース)する必要があります。

ここでは、カスタムフォーマットのファイルを読み込み、その内容を表示する例を紹介します。

#include <iostream>
#include <fstream>

struct MyData {
    int id;
    double value;
    char name[10];
};

int main() {
    MyData data;
    std::ifstream file("custom.bin", std::ios::binary);

    if (!file) {
        std::cerr << "ファイルを開けませんでした。" << std::endl;
        return 1;
    }

    file.read(reinterpret_cast<char*>(&data), sizeof(data));

    std::cout << "ID: " << data.id << ", Value: " << data.value << ", Name: " << data.name << std::endl;

    file.close();
    return 0;
}

このコードでは、カスタムバイナリファイルからデータを読み込み、構造体を通じてその内容を取得しています。

このような読み込みと解析のプロセスは、カスタムバイナリファイルを効果的に使用する上で重要なステップです。

●C++におけるバイナリファイル操作のコツとテクニック

C++でバイナリファイルを効果的に操作するためには、いくつかの重要なコツとテクニックがあります。

特に、メモリ管理とパフォーマンスの最適化は重要な要素です。

これらを理解し、適切に活用することで、C++でのバイナリファイルの操作をより効率的かつ安全に行うことができます。

○メモリ管理の重要性

バイナリファイルを扱う際、特に大きなファイルを取り扱う場合には、メモリ管理が非常に重要になります。

効率的なメモリ管理を行うことで、アプリケーションのパフォーマンスを保ちながら、システムリソースを適切に利用することができます。

例えば、ファイルを一度にメモリに読み込むのではなく、必要な部分だけを順次読み込む「ストリーミング」方式を取り入れることが有効です。

これにより、大きなファイルでもメモリ消費を抑えつつ、効率的に処理を行うことが可能になります。

○パフォーマンスと効率化のためのテクニック

バイナリファイルの操作において、パフォーマンスの最適化も欠かせない要素です。

ファイルの読み書きにかかる時間を短縮するために、バッファリング技術を利用することが推奨されます。

バッファリングを用いることで、ディスクへのアクセス回数を減らし、I/O操作の効率を高めることができます。

また、ファイルの読み書き処理を非同期に行うことで、他の処理との並行実行が可能になり、アプリケーション全体のレスポンスの改善に繋がります。

まとめ

この記事では、C++を用いたバイナリファイルの操作について、基本から応用まで幅広く解説しました。バ

イナリファイルの読み書き方法、エラーハンドリング、カスタマイズの手法、そして効率的なコードの書き方まで、初心者から上級者までが学べる内容を紹介しました。

C++の強力な機能を活用して、バイナリファイルの効率的な操作をマスターしましょう。