C/C++でバイナリファイルを読み書きする

標準ライブラリ関数を用いたC++でのバイナリファイル操作について解説します。特に、Android開発など、Windows APIやサードパーティ製ライブラリの使用が制限される環境で役立つ手法に焦点を当てます。

バイナリデータの逐次読み書き

以下のコードは、バイナリデータをチャンクごとに読み書きする基本的な方法を示しています。


#include <fstream>
#include <iostream>

bool copyBinaryFile(const char* sourcePath, const char* destinationPath) {
    std::ifstream sourceFile(sourcePath, std::ios::binary);
    std::ofstream destinationFile(destinationPath, std::ios::binary | std::ios::app);

    if (!sourceFile.is_open() || !destinationFile.is_open()) {
        return false;
    }

    char buffer[256];
    while (sourceFile.read(buffer, sizeof(buffer))) {
        if (!destinationFile.write(buffer, sizeof(buffer))) {
            return false;
        }
    }

    // 最後のチャンクでreadがfalseになった場合でも、eof()でチェック
    if (!sourceFile.eof()) {
        return false;
    }

    sourceFile.close();
    destinationFile.close();
    return true;
}
  

この方法は、構造体などのバイナリデータを扱う場合に有効ですが、画像ファイルのようにファイル全体を一度にメモリに読み込む必要がある場合には、効率が悪くなることがあります。

ファイル全体をメモリに読み込む

ファイル全体を一度にメモリに読み込むためのC++およびC言語での実装例を以下に示します。

C++での実装


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

int main() {
    const char* filename = "data.bin";
    std::ifstream inputFile(filename, std::ios::binary | std::ios::ate);

    if (!inputFile.is_open()) {
        std::cerr << "Error opening file." << std::endl;
        return 1;
    }

    std::streamsize fileSize = inputFile.tellg();
    inputFile.seekg(0, std::ios::beg);

    // std::vectorを使用してメモリを管理
    std::vector<char> buffer(fileSize);

    if (!inputFile.read(buffer.data(), fileSize)) {
        std::cerr << "Error reading file." << std::endl;
        return 1;
    }

    inputFile.close();

    // ファイルの内容を標準出力に書き出す例
    std::cout.write(buffer.data(), fileSize);

    return 0;
}
  

C言語での実装


#include <cstdio>
#include <cstdlib>
#include <iostream>

int main() {
    const char* filename = "data.bin";
    FILE* pFile = nullptr;
    long fileSize = 0;
    char* buffer = nullptr;
    size_t bytesRead = 0;

    pFile = fopen(filename, "rb");
    if (pFile == NULL) {
        perror("Error opening file");
        return 1;
    }

    // ファイルサイズを取得
    fseek(pFile, 0, SEEK_END);
    fileSize = ftell(pFile);
    rewind(pFile);

    // メモリを確保
    buffer = (char*)malloc(sizeof(char) * fileSize);
    if (buffer == NULL) {
        perror("Memory allocation error");
        fclose(pFile);
        return 1;
    }

    // ファイルを読み込む
    bytesRead = fread(buffer, 1, fileSize, pFile);
    if (bytesRead != (size_t)fileSize) {
        perror("Error reading file");
        fclose(pFile);
        free(buffer);
        return 1;
    }

    fclose(pFile);

    // ファイルの内容を標準出力に書き出す例
    // printf("%s", buffer); // 文字列として扱う場合
    std::cout.write(buffer, fileSize); // バイナリデータとして扱う場合

    free(buffer);
    return 0;
}
  

タグ: C++ C バイナリファイル ファイルI/O ストリーム

8月9日 15:48 投稿