ホーム 主筆 その他ソフト その他情報 Syuhitu.org English

Windows関連

スクリーンセーバー作成法

半透明ウインドウの性能

bootfont.bin

キャビネット形式

ウインドウスタイルをいじる

Java製ソフトをServiceに登録する

イベントログにメッセージを出力する

コントロールパネルにアイコンを追加する

スクリプトによる拡張1

スクリプトによる拡張2

ガジェットの作成

大容量メモリ

メモリ搭載量の下限に挑む

スパースファイルにする

Solaris関連

OpenGL

Solaris設定

ディレクトリの読み込み

主筆プラグイン開発

マルチスレッドでの開発

door

音を出す

Blade100の正しい虐め方

パッケージの作成

画像入出力

BMPファイル

ICOファイル

ANIファイル

JPEGファイル

減色アルゴリズム

減色アルゴリズムの並列化

その他アルゴリズムなど

自由軸回転

Base64

文字列操作

CPU利用率の取得

正規表現ライブラリ

メタボールを作る

メタボールを作る2

正規表現とNFA・DFA

C言語の構文解析

液晶ディスプレイを解体してみた

キャビネット形式を使おう

2006年7月29日公開

始めに

世の中には数多くのファイル圧縮形式が有りますが、その中にキャビネット形式と言う形式があります。これは、マイクロソフトが作成した圧縮形式で、よく、アプリケーションの配布用に使用されています。

そして、キャビネット形式で圧縮するためのソフトとしてmakecab.exeというソフトが存在します。ここでは、そのmakecab.exeの使用方法を紹介しようと思います。

キャビネット形式について

makecab.exeの紹介の前に、この圧縮形式について説明したいと思います。

この圧縮形式は上記の通り、アプリケーションの配布用に多く使用されます。例えば、一般に言われるパッケージソフトのインストーラーというのは、アプリケーションプログラムをこのキャビネット形式で圧縮したものと、それらを展開して必要な設定を施すソフトとを同梱したものです。

キャビネット形式で圧縮されたファイルの拡張子は、「*.cab」か、元のファイルの拡張子の最後の一文字を「_(アンダスコア)」に置き換えたものとなります。たとえば、「××.dll」というファイルを圧縮したら「××.dl_」となります。

また、この圧縮形式の最大の特徴は、「エクスプローラーが直接対応していること」です。別にこの圧縮自体の特徴ではないのですが、使う上ではこの上もなく便利です。

もし、ハードディスク上に「*.cab」というファイルが有ったらそれを、ダブルクリックしてみてください。また、拡張子の最後がアンダスコア終わっているファイルが有ったら、そのファイルの拡張子をcabに修正してからダブルクリックしてみてください。

おそらく、何かの圧縮ツールが関連付けをいじっていなければ、見慣れたエクスプローラーの画面が表示されると思います。この画面からドラッグアンドドロップでファイルを取得することができます。でも、ファイルを追加することはできません。

「d:\disk1」に「1.cab」というキャビネット形式のファイルがある。
「1.cab」をダブルクリックすると、その中に格納されているファイルが表示される。

WindowsXPでは、同様以上の機能が「*.zip」ファイルに対してもサポートされることとなりましたが、キャビネット形式はWindows95でもサポートされています。(それ以前のものは分かりません。)

それ以外の特徴としては以下の事柄が挙げられます。

  • 圧縮率が高い
  • 圧縮時間が長い
  • フォルダの圧縮が面倒

以上の事柄を見ると、やっぱりアプリケーションの配布用に作成されたものであることが伺えます。

makecab.exeの入手方法

このソフトは気がつくとPC内に入っていたりするものですが、無い場合は以下のサイトからダウンロードすることができます。

http://support.microsoft.com/default.aspx?scid=kb;ja;310618

このソフトは、インストールしても「スタート」メニューの中や、デスクトップに姿を現しません。ディスク内を「makecab.exe」で検索して探してください。そして見つかったらそのファイルをパスの通ったディレクトリに移動するか、そのディレクトリにパスを通してください。

使用方法

このソフトはコマンドラインで使用するソフトです。ウインドウベースでは使用できません。

とりあえず、makecabとコマンドを叩いてみます。

すると使用方法が表示されます。が、英語だし、何言ってるんだか、よく分かりません。

でも、だいたい以下の様なことを言っています。

  • スイッチ「/V1」「/V2」「/V3」は、圧縮の進捗状況の表示を、どれぐらい詳細に表示するかを指定します。これは省略可能です。
  • スイッチ「/D」はいろいろなオプションを設定するときに使用します。これについては後述します。このスイッチは省略可能です。
  • スイッチ「/L」は圧縮後のファイルを出力先(ディレクトリ)を指定します。このスイッチは省略可能です。省略した場合はカレントのディレクトリに出力されます。
  • スイッチ「/F」は圧縮するファイル名を記述したファイルを指定するためのスイッチです。このスイッチに指定したファイルに記述されているファイルを圧縮します。このスイッチを指定しない場合は、下記のsourceに指定したファイルが圧縮されます。
  • 「source」には圧縮するファイルを指定します。
  • 「destination」には圧縮後のファイル名を指定します。これは省略できますが、省略した場合は元のファイル名の最後の一文字が「_」に置き換えられたものとなります。

また、/Fのスイッチを指定した場合、「destination」は指定できません。エラーとなります。また、/Fを指定した場合/Lのスイッチは無視されます。出力先はカレントのディレクトリで、圧縮後のファイルの容量に合わせ「disk1」「disk2」というディレクトリが作成され、その中に「1.cab」というファイルが作成されます。

さらに、/Fスイッチを使用しない場合は、圧縮できるファイルは一つだけです。複数のファイルを一つのキャビネット形式にまとめるには「/F」スイッチを使用する必要があります。

用例

だいたいの使用例を下記に示します。

単一のファイルを圧縮する

makecab ファイル名

単一のファイルを圧縮します。圧縮後のファイルはカレントディレクトリに作成されます。作成されるファイル名は「ファイル名」に指定したファイルの、最後の一文字をアンダスコアに置き換えたものです。

makecab /L ディレクトリ名 ファイル名

単一のファイルを圧縮します。出力先のディレクトリは「ディレクトリ名」に指定したディレクトリとなります。作成されるファイル名は「ファイル名」に指定したファイルの、最後の一文字をアンダスコアに置き換えたものです。

makecab ファイル名 出力先ファイル名

単一のファイルを圧縮します。出力先はカレントのディレクトリです。作成されるファイルは「出力先ファイル名」に指定したファイル名です。

makecab /F ファイル名を記述したファイル

複数個のファイルを圧縮します。圧縮対象のファイルは「ファイル名を記述したファイル」内に記述されているファイルです。出力先はカレントのディレクトリとなります。

makecab /F ファイル名を記述したファイル1 /F ファイル名を記述したファイル2

「ファイル名を記述したファイル」を複数個指定する場合です。

単一のファイルを圧縮する場合は、上記の説明で終了です。ここからは、/Fスイッチを使用し、複数のファイルを圧縮する場合について説明します。

/Fスイッチに指定するファイルについて

/Fスイッチに指定するファイルには、上述の通りファイル名を記述します。そうすると、その記述したファイルが圧縮されます。

記述方法は下記のようになります。

ファイル名1
ファイル名2
ファイル名3

ただ、1行に1つずつファイル名を記述していけば良いだけです。

また、記述するファイル名は絶対パスでも、相対パスでも問題有りません。相対パスの場合はカレントからのパスとなります。

ただし、ファイル名の途中に空白を含むことができません。しかしこれでは、空白を含むファイルは圧縮できないこととなってしまします。そのため、ファイル名をダブルクォーテーションで囲むことができます。

よって、下記のように記述するのがより良いといえます。

"ファイル名1"
"ファイル名2"
"ファイル名3"

/Fスイッチに指定するファイルを横着して作成する方法

さて、ここで、圧縮するファイルがすごく多かった場合の事を考えてみます。

当然、/Fに指定するためのファイルを作らなくてはいけないのですが、ファイルが多くなると非常に面倒なことになります。

そこで、私はこのようにしています。

Dirコマンドで、ファイル名の一覧を生成させる。

Dirコマンドに/Sと/Bのスイッチをつけると、絶対パスで良い感じのファイル名の一覧を表示してくれます。ですから、それをリダイレクトしてファイルに書き込ませます。

Dir /S /B 一覧を表示するディレクトリ > ファイル名

ファイル名にダブルクォーテーションをつける

ファイル名にダブルクォーテーションが含まれていないことがはっきりしていれば、上記の方法だけで問題ないのですが、空白が含まれている場合は、ファイル名をダブルクォーテーションでくくってあげる必要があります。

下記のようなCのプログラムを咬ませるか、あるいはforコマンドでどうにかするか、エディタを使って根性で修正するしか方法はありません。

Cで処理する場合。

#include <stdio.h>

void main()
{
  int c, f = 1;

  // 最初の文字を取得
  c = getchar();

  // ファイルの末尾まで繰り返す
  while ( c != EOF ){
    // フラグが設定されていたら、
    // ダブルクォーテーションを出力する
    if ( f ){
      putchar( '\"' );
      f = 0;
    }
    // 改行コード前にダブルクォーテーションを出力する
    if ( c == '\n' ){
      putchar( '\"' );
      // 行頭にダブルクォーテーションを
      // 出力させるためにフラグを設定する
      f = 1;
    }
    // 文字を出力する
    putchar( c );
    // 次の文字を読み込む
    c = getchar();
  }
}

forコマンドで頑張る場合

for /F "delims=" %I IN ( 'dir /S /B フォルダ名' ) DO echo "%I" >> 出力先

ついでにいうと、上記のforコマンドはWindows2000以上でなければ使えません。NT4.0で使えるかどうかは判りません。

出力先のファイルサイズを指定する方法

さて、これで基本的な使用方法は全て説明したことになります。

しかし、一つ大きな問題があります。それは「/Fスイッチを指定した場合、出力されるファイルが約1.38MBごとに区切られる」ということです。つまり、圧縮後のファイルサイズが1.38MBを超える場合は、ファイルが複数作成されてしまうと言うことです。

確かにアプリケーションをFDに入れて配布する場合は非常に都合が良いのですが、単に圧縮したい場合や、FD以外の媒体に格納したい場合は困ったことになります。

そこで役に立つのが、「/D」スイッチです。

/Dスイッチを使用して、以下のように指定します。

makecab /D MaxDiskSize=バイト数 /F ファイル名

出力先のキャビネットファイルはMaxDiskSizeに指定したバイト数ごとに区切られて出力されます。当然、十分に大きな値を指定すれば単一のファイルにまとめて出力させることができます。

そのほかの指定可能な項目

/Dスイッチにはそのほかにも、指定可能な項目が存在します。以下に知っている限り記述します。

項目 機能 使用例
RptFileName 「setup.rpt」というファイルの名前を変更します。 /D RptFileName=abc.txt
InfFileName 「setup.inf」というファイルの名前を変更します。 /D InfFileName=abc.txt
InfCommentString 「setup.inf」中のコメントアウト用の記号を指定します。 /D InfCommentString=#
InfFileHeader 「setup.inf」中の「[file list]」セクションの名称を指定します。 /D InfFileHeader=[HOGEHOGE]
InfFileLineFormat 「setup.inf」中の「[file list]」セクション内のフォーマットを指定します。 /D InfFileLineFormat=*disk#*,*cab#*,*file*,*size*
InfDiskHeader 「setup.inf」中の「[disk list]」セクションの名称を指定します。 /D InfDiskHeader=[HOGEHOGE]
InfDiskLineFormat 「setup.inf」中の「[disk list]」セクション内のフォーマットを指定します。 /D InfDiskLineFormat=*disk#*,*label*
InfCabinetHeader 「setup.inf」中の「[cabinet list]」セクションの名称を指定します。 /D InfCabinetHeader=[HOGEHOGE]
InfCabinetLineFormat 「setup.inf」中の「[cabinet list]」セクションのフォーマットを指定します。 /D InfCabinetLineFormat=*cab#*,*disk#*,*cabfile*
InfSectionOrder 「setup.inf」中のセクションの並びを指定します。 /D InfSectionOrder=FCD
InfHeader 「setup.inf」中の1行目に出力する文字列を変更します。 /D InfHeader=%1+++++++++
InfHeader1 「setup.inf」中の2行目に出力する文字列を変更します。 /D InfHeader1=%1+++++++++
InfHeader2 「setup.inf」中の3行目に出力する文字列を変更します。 /D InfHeader2=%1+++++++++
InfHeader3 「setup.inf」中の4行目に出力する文字列を変更します。 /D InfHeader3=%1+++++++++
InfHeader4 「setup.inf」中の5行目に出力する文字列を変更します。 /D InfHeader4=%1++++%3+++
InfHeader5 「setup.inf」中の6行目に出力する文字列を変更します。 /D InfHeader5=%1+++++++++
InfHeader6 「setup.inf」中の7行目に出力する文字列を変更します。 /D InfHeader6=%1+++++++++
InfFooter 「setup.inf」中のフッタのコメントの1行目に出力する文字列を変更します。 /D InfFooter=%1+++++++++
InfFooter1 「setup.inf」中のフッタのコメントの2行目に出力する文字列を変更します。 /D InfFooter1=%1+++++++++
InfFooter2 「setup.inf」中のフッタのコメントの3行目に出力する文字列を変更します。 /D InfFooter2=%1+++++++++
InfFooter3 「setup.inf」中のフッタのコメントの4行目に出力する文字列を変更します。 /D InfFooter3=%1+++++++++
InfFooter4 「setup.inf」中のフッタのコメントの5行目に出力する文字列を変更します。 /D InfFooter4=%1+++++++++
DiskLabelTemplate 「setup.inf」中の「[disk list]」エントリ内のディスクのラベルの命名規則を変更します。*は通番を示します。 /D DiskLabelTemplate=HOGE*
DiskDirectoryTemplate 生成する「Disk1」「Disk2」・・・というフォルダの命名規則を設定します。*は通番を示します。 /D DiskDirectoryTemplate=HOGE*
CompressionType 圧縮方法を指定します。LZXとMSZIPが指定できます。 /D CompressionType=LZX
CabinetNameTemplate 生成される*.cabファイルの命名規則を指定します。*は通番を示します。 /D CabinetNameTemplate=HOGE*.cab
MaxCabinetSize 生成されるキャビネットファイルの上限を設定します。 /D MaxCabinetSize=1024000
MaxDiskSize 生成されるディレクトリ1つあたりのサイズの上限を設定します。MaxCabinetSize<MaxDiskSizeの場合、1つのフォルダ内に複数個のキャビネットファイルが生成されます。MaxCabinetSize>MaxDiskSizeの場合、MaxDiskSizeは無視されます。 /D MaxDiskSize=1024000
ClusterSize クラスタのサイズを指定します。MaxCabinetSizeやMaxDiskSizeはClusterSizeの倍数である必要があります。 /D ClusterSize=1024

※補足

  • 複数個の項目を指定したい場合は、/D XXX1=YYY2 /D XXX2=YYY2と、各項目ごとに/Dをつけてください。
  • 文字列を指定する項目(infファイルのヘッダやフッタ)に、空白を指定したい場合は指定する値をダブルクォーテーションでくくることができます。(例 /D InfHeader="%1 HOGEHOGE ")
  • InfHeaderからInfFooter4までに指定する文字列中には、%1、%2、%3を指定できます。
    %1 コメントアウト用の記号、InfCommentStringに指定した値。
    %2 圧縮時の日付
    %3 圧縮に使用したmakecab.exeのバージョン
  • InfFileLineFormatに指定する値は、以下のものが指定できます。
     *disk#* ディスク番号
     *cab#* キャビネット番号
     *file*  圧縮したファイル名
     *size* 圧縮前のファイルのサイズ
  • InfDiskLineFormatに指定する値は、以下のものが使用できます。
     *disk#* ディスク番号
     *label* ラベル
  • InfCabinetLineFormat
     *cab#* キャビネット番号
     *disk#* ディスク番号
     *cabfile* キャビネットファイルのファイル名
  • /Dを使用したオプションの設定は、/Fスイッチを使用する場合でも、単一のファイルを圧縮する場合でも使用可能です。

こうやってみると、infファイルに出力する内容は、極めて自由度が高いことに気がつきます。おそらくこれは、「インストーラが参照するためのファイルを生成する」という目的から来ているのではないかと思われます。

自己解凍形式にする

キャビネット形式でも、一応自己解凍形式にすることができます。

自己解凍形式にするには、CabinetSDK中に含まれるEXTRACT.EXEというファイルと、通常のキャビネット形式のファイルとを連結します。

たとえば、a.cabを自己解凍形式のa.exeにするなら、

copy /B EXTRACT.EXE+a.cab a.exe

とすればいいそうです。

フォルダの圧縮

上述の方法だと、フォルダ階層をそのままの形で圧縮することができません。

しかし、/Fスイッチに指定するファイルに、展開先ディレクトリを指定する記述を書き加えれば、フォルダごと圧縮することもできます。

例えば、下記のようなフォルダ階層を圧縮することを考えます。なお、FLD01はc:\に格納されているものとします。

FLD01
a.txt
b.bmp
FLD02
c.txt
d.xls

展開先ディレクトリを指定するには、/Fに指定するファイル中に下記のような記述を追記します。

.Set DestinationDir=展開先フォルダ

このように記述すると、その記述より下に書かれたファイルは、「展開先フォルダ」に指定されたフォルダに展開されることになります。

なので、上記の例であれば、このようなファイルを作成してあげることになります。

.Set DestinationDir="FLD01"
"c:\FLD01\a.txt"
"c:\FLD01\b.bmp"
.Set DestinationDir="FLD01\FLD02"
"c:\FLD01\FLD02\c.txt"
"c:\FLD01\FLD02\d.xls"

上記のファイルを使って圧縮したキャビネットファイルを、エクスプローラーで見ると、このようになります。

パスの情報が記録されていることが判ります。

ただ、これをこのままドラッグ&ドロップで展開しようとしても、できません。全部同じところに展開されてしまいます。

フォルダ階層を正しく再現するためには、EXTRACT.EXEを使う必要があります。

自己解凍形式に変換するか、あるいは下記のコマンドで展開する必要があります。

EXTRACT /E キャビネットファイルの名前

そうすると、カレントディレクトリにFLD01が作成され、その中にa.txtやFLD02等のファイルが展開されます。