投稿者 tel | 2012年4月28日

ファイルをアーカイブ化する

小さなサイズのファイルは1つ1つ読み込みをするよりも、まとめて読み込んだほうが読み込み時間が短くなる。そのためゲームでは複数のファイルを1つにまとめるアーカイブ化をする場合が多い。
すごく簡単なファイルのアーカイブ化を作ってみる。
ファイル数と内部のファイルへの先頭からのオフセットを保持する。
ファイルの名前やディレクトリ構造は保持しない。そういったものを管理するには辞書を扱えるようなデータ構造(トライ木、パトリシア木など)が必要。手軽にやるならzipとかをつかえばよさそう。(ゲームエンジンアーキテクチャではzlibがオススメされていた)

使い方は、アーカイブ化されたファイルを読み込んでメモリに置く。インデックス指定で必要なファイルデータのアドレスを取得する。

struct SimpleArchiveHeader {
    unsigned int fileCount;
    unsigned int offsets[1];

    void *GetFile(int index)
    {
        if(index < fileCount) {             return reinterpret_cast(reinterpret_cast(this) + offsets[index]);         } else {             return NULL;         }     }     size_t GetFileSize(int index)     {         if(index >= fileCount) {
            return 0;
        }

        return offsets[index + 1] - offsets[index];
    }
};

引数に複数ファイル渡された場合はアーカイブファイルを出力する。

#include
#include
#include
#include "archive.h"

using namespace std;

int main(int argc, char *argv[])
{
    SimpleArchiveHeader arc;
    vector< pair > files;

    cout << "argc " << argc << endl;

    if(argc == 2) {
        // アーカイブ化したファイルを読み込む

        ifstream ifs(argv[1], ifstream::binary);
        ifs.seekg(0, ios::end);
        size_t length = ifs.tellg();
        ifs.seekg(0, ios::beg);

        char *buffer = new char[length];
        ifs.read(buffer, length);
        SimpleArchiveHeader *arc = reinterpret_cast(buffer);

        cout << arc->fileCount << endl;
        cout << GetArchiveFileSize(arc, 1) << endl;         const char *data = static_cast(arc->GetFile(1));
        for(int i = 0; i < arc->GetFileSize(1); i++) {
            cout << static_cast(data[i]);         }         delete buffer;     } else if(argc > 2) {
        // ファイルをアーカイブ化する
        for(int i = 0; i < argc - 1; i++) {
            cout << argv[i + 1] << endl;

            ifstream ifs(argv[i + 1], ifstream::binary);
            ifs.seekg(0, ios::end);
            size_t length = ifs.tellg();
            ifs.seekg(0, ios::beg);

            char *buffer = new char[length];
            ifs.read(buffer, length);
            files.push_back(make_pair(buffer, length));
        }

        int count = files.size();
        ofstream ofs("out.arc", ios::binary);
        ofs.write(reinterpret_cast(&count), sizeof(count));
        unsigned int offset = sizeof(count);
        offset += (count + 1) * sizeof(offset);
        for(int i = 0; i < count; i++) {
            ofs.write(reinterpret_cast(&offset), sizeof(offset));
            offset += files[i].second;
        }
        ofs.write(reinterpret_cast(&offset), sizeof(offset));
        for(int i = 0; i < count; i++) {
            ofs.write(reinterpret_cast(files[i].first), files[i].second);
        }
    }

    return 0;
}
ゲームエンジン・アーキテクチャ

ゲームエンジン・アーキテクチャ

posted with amazlet at 12.04.28
ジェイソン・グレゴリー
ソフトバンククリエイティブ
売り上げランキング: 160919

ファイルをアーカイブ化する – その2

ファイルをアーカイブ化する – その3


Responses

  1. […] ファイルをアーカイブ化する […]


コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

カテゴリー

%d人のブロガーが「いいね」をつけました。