Delphi Programming / Object Pascal
[掲載 2014年10月23日] [更新 2015年03月21日] Delphi サンプルプログラム集
742_Tar32.dll を使用したファイルの圧縮・解凍
動作確認等
Windows 7 U64(SP2) + Delphi X(UP1) Pro + Tar32.dll 2.42.0.1
742_tar32dll_Test.zip [2,472 KB] 2015年03月21日版 (EXE 同梱)
2015年03月21日
進捗状況を表示するサンプルを追加
アーカイブコマンドに -z を追加 (圧縮しない単なるアーカイブだけだった)
Tar32.dll を使用したファイルの圧縮・解凍
Tar32.dll を使用したファイルの圧縮・解凍のサンプルです.
Tar32.dll を使用すると,現在,UNIX 系の OS でよく使用されている 拡張子が .tar.gz 等のファイルの圧縮や解凍ができます.gz は GZIP 形式の圧縮を意味します.
UNIX 系のコンピュータでは,テープでバックアップの意味で TAR (テープアーカイバー) が使用されています.これは圧縮ではありません.tar でアーカイブしたファイルをパイプで gzip すると,tarでアーカイブしながら同時に gzip で圧縮します.つまり,アーカイブして圧縮すると .tar.gz いう拡張子となります.拡張子が .gz の gzip 自体にはアーカイバ (複数のファイルの格納) の機能はありません..gz で格納できるファイルは 1 つだけです.
Tar32.dll で扱える書庫形式については,以下で確認してください.
Tar32.dll は [総合アーカイバプロジェクト] のページからダウンロードできますが,以下の作者のサイトからもダウンロードできます.
コード内の DLL のコマンドラインスイッチの説明は,DLL に説明書が添付されています.
Tar32.dll の API (DLL 内の関数) と コマンド (関数の引数) の説明は,最新のバージョンには詳しい説明がありません.以下のリンクの記事にある [TAR32.DLL Ver0.xx(古いバージョン)] の [パッケージ] のページからダウンロードすると,その中にあります.
当サイトには,この他,以下のようなアーカイブファイルの圧縮・解凍関係のサンプルがあります.これらの記事中のリンクも参考にしてください.
01_ Tar32.dll 内の Tar 関数を使用したファイルの解凍
Tar32.dll を使用するということは,DLL を使用するということです.DLL を使用するということは,DLL 内の関数類を使用するということになります.
本サンプルでは,DLL をシステムに登録しないで利用することにしています.そこで,DLL を EXE と同じフォルダに置いて使用します.DLL は LoadLibrary でロードし,終了時に FreeLibrary で解放しています.圧縮した書庫ファイルの解凍だけのサンプルとなっています.解凍には,Tar32.dll 内の Tar という関数を使用します.この関数 Tar の引数の値で圧縮か解凍を指定し,ファイル名やオプション等も関数の引数として指定します.
下の図は添付の test.tar.gz というファイルを,[Temp] というフォルダに解凍した結果です.
[備考]
Tar32.dll がシステムに登録されている場合,この Tar32.dll を EXE と同じフォルダに置く必要はありません.システムに登録した時の場所から自動的に読み込まれます.
図1
設計時画面
図2
解凍する書庫の内容
Tar32.dll 内の関数を利用すれば,この図のような書庫内のファイルの表示もできる
図3
上の図のファイルを解凍した結果
リスト1
Tar32.dll 内の Tar 関数を使用したファイルの解凍
DLL を動的 (実行時) にロードして使用する場合
copy code
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class (TForm)
OpenDialog1: TOpenDialog;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
function ExtractTar(SrcPath, DestPath: String ; var AMsg: String ): Boolean;
public
{ Public 宣言 }
end ;
var
Form1: TForm1;
implementation
{$R *.dfm}
type
TTarFunc = function (const hWnd: HWND; szCmdLine: LPCSTR; szOutPut: LPSTR;
constdwSize: DWORD): Integer; stdcall ;
// =============================================================================
// tar32.dllを使用した書庫ファイルの解凍のテスト
// 解凍先のディレクトリがない場合は自動作成して上書き保存
//
// tar32.dllで扱える書庫の例
// -----------------------------------------------------
// 形式 定数名 定数値
// -----------------------------------------------------
// TAR ARCHIVETYPE_TAR 1
// TAR.GZ(TGZ) ARCHIVETYPE_TARGZ 2
// TAR.Z(TAZ) ARCHIVETYPE_TARZ 3 展開のみ
// GZ(GZIP) ARCHIVETYPE_GZ 4
// Z ARCHIVETYPE_Z 5 展開のみ
// TAR.BZ2 ARCHIVETYPE_TARBZ2 6
// BZ2 ARCHIVETYPE_BZ2 7
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
SrcFile : String ;
DestDir : String ;
ResultMsg : string ;
flgResult : Boolean;
begin
// 解凍対象の書庫ファイルを選択
OpenDialog1.InitialDir := ExtractFileDir(ParamStr(0 ));
OpenDialog1.Filter := 'tar (TGZ,TAZ,BZ2) 書庫|*.tar.gz;*.tar.z;*.tar.bz2|' +
'tar 書庫|*.tar|' +
'gz (GZIP) 書庫|*.gz|' +
'z 書庫|*.z|' +
'bz2 (BZIP2) 書庫|*.bz2|' ;
OpenDialog1.FileName := '' ;
if not OpenDialog1.Execute then exit;
// SrcFileは解凍する対象のファイルのフルパス
// DestDirは解凍したファイルを格納するディレクトリ名のフルパス
SrcFile := OpenDialog1.FileName;
DestDir := ExtractFilePath(Application.ExeName)+ 'Temp' ;
// 解凍
flgResult := ExtractTar(SrcFile, DestDir, ResultMsg);
if flgResult then begin
MessageBox(Handle, '解凍終了' , '実行結果' , MB_ICONINFORMATION);
end else begin
MessageBox(Handle, '解凍失敗' , '実行結果' , MB_ICONSTOP);
end ;
end ;
// -----------------------------------------------------------------------------
// tar32.dll内のTarという関数を使用して書庫を解凍する
// -----------------------------------------------------------------------------
function TForm1.ExtractTar(SrcPath, DestPath: String ;
var AMsg: String ): Boolean;
const
BUFF_SIZE = 8192 ;
var
DllHandle : THandle;
TarFunc : TTarFunc;
Command : AnsiString;
Output : array [0 ..BUFF_SIZE-1 ] of AnsiChar;
begin
Result := False;
// DLLをロード
DllHandle := LoadLibrary('tar32.dll' );
if DllHandle < HINSTANCE_ERROR then exit;
try
// DLL内のTarという関数のアドレスを取得
@TarFunc := GetProcAddress(DllHandle, 'Tar' );
if @TarFunc = nil then exit;
// ヒントや警告が表示されるので明示的にキャストしておく
Command := AnsiString('-x --display-dialog=0 ' +
AnsiQuotedStr(SrcPath, '"' ) + ' ' +
AnsiQuotedStr(IncludeTrailingPathDelimiter(DestPath), '"' ));
FillChar(Output, SizeOf(Output), 0 );
try
// 実際にDLL内の関数を実行する部分
TarFunc(Handle, PAnsiChar(Command), OutPut, BUFF_SIZE);
AMsg := String (OutPut);
Result := True;
except
end ;
finally
FreeLibrary(DllHandle);
end ;
end ;
end .
02_ Tar32.dll 内の関数類を利用するクラスを作成
Tar32.dll の関数を使用するコードを,以下のリンクのサンプルのように,クラスにする例です.
単に DLL 内の関数を使用する定義だけのコードをユニットにするだけでもいいのですが,クラスとして構成しておくと便利です.
圧縮と解凍だけの実装になっています.圧縮は .tar.gz 専用となっています.
下の図とコードは,作成したクラスをテストしたコードと実行結果です.
図4
設計時画面
図5
圧縮するフォルダ
[AAA] フォルダ内のファイル全てを格納した書庫を作成する
図6
作成した書庫
[Temp] フォルダ内に Test.tar.gz ができる
図7
作成した書庫を解凍した結果
リスト2
Tar32.dll 内の関数類を利用するクラスを使用したサンプル
copy code
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class (TForm)
OpenDialog1: TOpenDialog;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end ;
var
Form1: TForm1;
implementation
uses plArchieverTAR;
{$R *.dfm}
// =============================================================================
// ファイルの圧縮
// 指定したディレクトリ内のファイル全てを.tar.gz形式で圧縮
// 以下のコードでは,プロジェクトのファルダ下の[Temp]フォルダ内に保存
//
// tar32.dllで扱える書庫の例
// -----------------------------------------------------
// 形式 定数名 定数値
// -----------------------------------------------------
// TAR ARCHIVETYPE_TAR 1
// TAR.GZ(TGZ) ARCHIVETYPE_TARGZ 2
// TAR.Z(TAZ) ARCHIVETYPE_TARZ 3 展開のみ
// GZ(GZIP) ARCHIVETYPE_GZ 4
// Z ARCHIVETYPE_Z 5 展開のみ
// TAR.BZ2 ARCHIVETYPE_TARBZ2 6
// BZ2 ARCHIVETYPE_BZ2 7
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
Arch : TplArchieverTAR;
FileDlg : TFileOpenDialog;
RetFlag : Boolean;
SrcDir : String ;
DestFile : String ;
ResultMsg : string ;
begin
// 初期選択フォルダパス
SrcDir := ExtractFilePath(Application.ExeName);
RetFlag := False;
// Windows Vista以降専用コード
FileDlg := TFileOpenDialog.Create(nil );
try
FileDlg.Options := [fdoPickFolders,
fdoPathMustExist,
fdoForceFileSystem];
if FileDlg.Execute then begin
Update;
SrcDir := FileDlg.FileName;
RetFlag := True;
end ;
finally
FreeAndNil(FileDlg);
end ;
if not RetFlag then exit;
Screen.Cursor := crHourGlass;
Arch := TplArchieverTAR.Create(Self);
try
// 圧縮後のファイル名(フルパス)
// このプロジェクトのフォルダとする
// PackFilesメソッドはフォルダが存在しないと自動作成する
DestFile := ExtractFilePath(Application.ExeName) + 'Temp' + PathDelim + 'Test.tar.gz' ;
// 圧縮
RetFlag := Arch.PackFiles(SrcDir, DestFile, ResultMsg);
finally
FreeAndNil(Arch);
Screen.Cursor := crDefault;
end ;
if RetFlag then begin
MessageBox(Handle, '圧縮終了' , '実行結果' , MB_ICONINFORMATION);
end else begin
MessageBox(Handle, '圧縮失敗' , '実行結果' , MB_ICONWARNING);
end ;
end ;
// =============================================================================
// 書庫の解凍
// 解凍先のディレクトリがない場合は自動作成して上書き保存
// 以下のコードでは,プロジェクトのフォルダ下の[Temp]フォルダ内に解凍
// =============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
Arch : TplArchieverTAR;
SrcFile : String ;
DestDir : String ;
ResultMsg : string ;
flgResult : Boolean;
begin
// 解凍対象の書庫ファイルを選択
OpenDialog1.InitialDir := ExtractFileDir(ParamStr(0 ));
OpenDialog1.Filter := 'tar (TGZ,TAZ,BZ2) 書庫|*.tgz;*.tar.gz;*.tar.z;*.tar.bz2|'
+ 'tar 書庫|*.tar|'
+ 'gz (GZIP) 書庫|*.gz|'
+ 'z 書庫|*.z|'
+ 'bz2 (BZIP2) 書庫|*.bz2|' ;
OpenDialog1.FileName := '' ;
if not OpenDialog1.Execute then exit;
Screen.Cursor := crHourGlass;
Arch := TplArchieverTAR.Create(Self);
try
SrcFile := OpenDialog1.FileName;
DestDir := ExtractFilePath(Application.ExeName) + 'Temp' ;
// 解凍
flgResult := Arch.Extract(SrcFile, DestDir, ResultMsg);
finally
FreeAndNil(Arch);
Screen.Cursor := crDefault;
end ;
if flgResult then begin
MessageBox(Handle, '解凍終了' , '実行結果' , MB_ICONINFORMATION);
end else begin
MessageBox(Handle, '解凍失敗' , '実行結果' , MB_ICONWARNING);
end ;
end ;
end .
作成したクラスのコードです.
コンストラクタ (Create メソッド) で DLL をロードし,デコンストラクタで DLL のハンドルを無効にしています.
リスト3
Tar32.dll 内の関数類を利用するクラスのユニット
copy code
unit plArchieverTAR;
interface
uses
Windows, Messages, SysUtils, Classes, Controls, Forms;
const
lpszWMARCEXTRACT = 'wm_arcextract' ;
type
TplArchieverTAR = class (TComponent)
private
FHandle : HWND;
protected
FDllHandle : THandle;
function Execute(Cmd: String ; var AMsg: String ): Boolean;
public
constructor Create( AOwner:TComponent ); override ;
destructor Destroy(); override ;
function Extract(SrcPath, DestPath: String ; var AMsg: String ): Boolean;
function PackFiles(SrcPath, DestPath: String ; var AMsg: String ): Boolean;
end ;
implementation
{ TplArchieverTAR }
type
TTar = function (const hWnd: HWND; szCmdLine: LPCSTR; szOutPut: LPSTR;
constdwSize: DWORD): Integer; stdcall ;
var
FTar : TTar;
// =============================================================================
// Create処理
// =============================================================================
constructor TplArchieverTAR.Create(AOwner: TComponent);
begin
inherited ;
FDllHandle := LoadLibrary('tar32.dll' );
if FDllHandle < HINSTANCE_ERROR then begin
FDllHandle := 0 ;
end else begin
FHandle := TWinControl(AOwner).Handle;
// DLL内のTarという関数のアドレスを取得
@FTar := GetProcAddress(FDllHandle, 'Tar' );
end ;
end ;
// =============================================================================
// Destroy処理
// =============================================================================
destructor TplArchieverTAR.Destroy;
begin
if FDllHandle <> 0 then begin
FreeLibrary(FDllHandle);
end ;
FDllHandle := 0 ;
inherited ;
end ;
// =============================================================================
// 圧縮メソッド
// SrcPath : 圧縮対象のディレクトリ名(このディレクトリ内のファイルを全て格納)
// DestPath : 圧縮後のファイル名のフルパス
//
// -----------------------------------------------------------------------------
// 圧縮の種類のコマンドオプションの例
//
// -z[N] gzip相当の圧縮.Nは圧縮レベルで1~9(デフォルトは6 )
// --gzip=[N] 同上
// -B[N] bzip2相当の圧縮.Nは圧縮レベルで1~9(デフォルトルは9)
// --bzip(=[N]) 同上
// --bzip2(=[N]) 同上
// -G gzipまたはbzip2相当の圧縮のみ実行
// -J[N] xz相当の圧縮.Nは圧縮レベルで1~9(デフォルトルは6)
// --xz(=[N]) 同上
// --lzma(=[N]) lzma相当の圧縮.Nは圧縮レベルで1~9(デフォルトルは6)
// =============================================================================
function TplArchieverTAR.PackFiles(SrcPath, DestPath: String ;
var AMsg: String ): Boolean;
var
FCommand : String ;
begin
Result := False;
if FDllHandle = 0 then exit;
ForceDirectories(ExtractFileDir(DestPath));
FCommand := '-c -z --display-dialog=0 ' +
AnsiQuotedStr(DestPath, '"' ) + ' ' +
AnsiQuotedStr(IncludeTrailingPathDelimiter(SrcPath), '"' ) + ' ' +
'*.*' ;
// 引数を与えて関数を実行
Result := Execute(FCommand, AMsg);
end ;
// =============================================================================
// 解凍メソッド
// SrcPath : 解凍対象のファイルのフルパス
// DestPath : 解凍したファイルを格納するディレクトリ
// =============================================================================
function TplArchieverTAR.Extract(SrcPath, DestPath: String ;
var AMsg: String ): Boolean;
var
FCommand : String ;
begin
Result := False;
if FDllHandle = 0 then exit;
FCommand := '-x --display-dialog=0 ' +
AnsiQuotedStr(SrcPath, '"' ) + ' ' +
AnsiQuotedStr(IncludeTrailingPathDelimiter(DestPath), '"' );
// 引数を与えて関数を実行
Result := Execute(FCommand, AMsg);
end ;
// =============================================================================
// 圧縮または解凍の実行ルーチン
// 圧縮か解凍かは引数のコマンドで決まる
// =============================================================================
function TplArchieverTAR.Execute(Cmd: String ; var AMsg: String ): Boolean;
const
BUFF_SIZE = 8192 ;
var
ACommand : AnsiString;
Output : array [0 ..BUFF_SIZE-1 ] of AnsiChar;
begin
Result := False;
if @FTar <> nil then begin
FillChar(Output, SizeOf(Output), 0 );
// ヒントや警告が表示されるので明示的にキャストしておく
ACommand := AnsiString(Cmd);
try
// 実際にDLL内の関数を実行する部分
// tar32.dll内のTarという関数を実行
FTar(FHandle, PAnsiChar(ACommand), OutPut, BUFF_SIZE);
Result := True;
except
end ;
end ;
AMsg := String (OutPut);
end ;
end .
前項のサンプルに,進捗状況を表示する機能を追加したテストです.
そのために,DLL を利用するクラス内のコードに,メッセージを送信するためのコードを追加しています.受信したメッセージから情報を取得するための構造体の定義も追加しています.圧縮は .tar.gz 専用のコードとなっています.
メッセージの値は WM_ARCEXTRACT となっています.総合アーカイバプロジェクトでは全てこの値を使用するようになっています.
図8
設計時画面
図9
圧縮中の画面
リスト4
Tar32.dll 内の関数類を利用するクラスを使用したサンプル
前項のサンプルにプログレスバー関係の処理を追加
copy code
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, ComCtrls;
type
TForm1 = class (TForm)
OpenDialog1: TOpenDialog;
Button1: TButton;
Button2: TButton;
ProgressBar1: TProgressBar;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
protected
procedure WndProc(var Message: TMessage); override ;
private
{ Private 宣言 }
FTotalSize : UInt64;
FWriteSize : UInt64;
procedure GetDirFilesSize(ADir: String ; var ASumSize: UInt64);
public
{ Public 宣言 }
end ;
var
Form1: TForm1;
implementation
uses plArchieverTAR, IOUtils;
{$R *.dfm}
// =============================================================================
// ファイルの圧縮
// 指定したディレクトリ内のファイル全てを.tar.gz形式で圧縮
// 以下のコードでは,プロジェクトのファルダ下の[Temp]フォルダ内に保存
//
// tar32.dllで扱える書庫の例
// -----------------------------------------------------
// 形式 定数名 定数値
// -----------------------------------------------------
// TAR ARCHIVETYPE_TAR 1
// TAR.GZ(TGZ) ARCHIVETYPE_TARGZ 2
// TAR.Z(TAZ) ARCHIVETYPE_TARZ 3 展開のみ
// GZ(GZIP) ARCHIVETYPE_GZ 4
// Z ARCHIVETYPE_Z 5 展開のみ
// TAR.BZ2 ARCHIVETYPE_TARBZ2 6
// BZ2 ARCHIVETYPE_BZ2 7
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
Arch : TplArchieverTAR;
FileDlg : TFileOpenDialog;
RetFlag : Boolean;
SrcDir : String ;
DestFile : String ;
ResultMsg : string ;
begin
// 初期選択フォルダパス
SrcDir := ExtractFilePath(Application.ExeName);
RetFlag := False;
// Windows Vista以降専用コード
FileDlg := TFileOpenDialog.Create(nil );
try
FileDlg.Options := [fdoPickFolders,
fdoPathMustExist,
fdoForceFileSystem];
if FileDlg.Execute then begin
Update;
SrcDir := FileDlg.FileName;
RetFlag := True;
end ;
finally
FreeAndNil(FileDlg);
end ;
if not RetFlag then exit;
Screen.Cursor := crHourGlass;
Arch := TplArchieverTAR.Create(Self);
try
// 圧縮後のファイル名(フルパス)
// このプロジェクトのフォルダとする
// PackFilesメソッドはフォルダが存在しないと自動作成する
DestFile := ExtractFilePath(Application.ExeName) + 'Temp' + PathDelim + 'Test.tar.gz' ;
// 圧縮するファイルのサイズを取得
FTotalSize := 0 ;
FWriteSize := 0 ;
GetDirFilesSize(SrcDir, FTotalSize);
ProgressBar1.Max := 1000 ;
// 圧縮
RetFlag := Arch.PackFiles(SrcDir, DestFile, ResultMsg);
finally
FreeAndNil(Arch);
Screen.Cursor := crDefault;
end ;
if RetFlag then begin
MessageBox(Handle, '圧縮終了' , '実行結果' , MB_ICONINFORMATION);
end else begin
MessageBox(Handle, '圧縮失敗' , '実行結果' , MB_ICONWARNING);
end ;
end ;
// =============================================================================
// 書庫の解凍
// 解凍先のディレクトリがない場合は自動作成して上書き保存
// 以下のコードでは,プロジェクトのフォルダ下の[Temp]フォルダ内に解凍
// =============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
Arch : TplArchieverTAR;
SrcFile : String ;
DestDir : String ;
ResultMsg : string ;
flgResult : Boolean;
begin
// 解凍対象の書庫ファイルを選択
OpenDialog1.InitialDir := ExtractFileDir(ParamStr(0 ));
OpenDialog1.Filter := 'tar (TGZ,TAZ,BZ2) 書庫|*.tgz;*.tar.gz;*.tar.z;*.tar.bz2|'
+ 'tar 書庫|*.tar|'
+ 'gz (GZIP) 書庫|*.gz|'
+ 'z 書庫|*.z|'
+ 'bz2 (BZIP2) 書庫|*.bz2|' ;
OpenDialog1.FileName := '' ;
if not OpenDialog1.Execute then exit;
Screen.Cursor := crHourGlass;
Arch := TplArchieverTAR.Create(Self);
try
SrcFile := OpenDialog1.FileName;
DestDir := ExtractFilePath(Application.ExeName) + 'Temp' ;
// アーカイブ内のファイルサイズを取得
FWriteSize := 0 ;
FTotalSize := Arch.GetOriginalSize(SrcFile);
ProgressBar1.Max := 1000 ;
// 解凍
flgResult := Arch.Extract(SrcFile, DestDir, ResultMsg);
finally
FreeAndNil(Arch);
Screen.Cursor := crDefault;
end ;
if flgResult then begin
MessageBox(Handle, '解凍終了' , '実行結果' , MB_ICONINFORMATION);
end else begin
MessageBox(Handle, '解凍失敗' , '実行結果' , MB_ICONWARNING);
end ;
end ;
// =============================================================================
// DLLから圧縮・解凍時のメッセージ受信
// ここではWndProcを使用
// プログレスバーに進捗状況を表示
//
// LPExtractingInfo,WM_ARCEXTRACT,ARCEXTRACT_XXXはplArchieverTAR.pas内の定義
// =============================================================================
procedure TForm1.WndProc(var Message: TMessage);
var
State : UINT;
lpEis : LPExtractingInfo;
begin
inherited ;
if Message.Msg = WM_ARCEXTRACT then begin
State := Message.wParam;
lpEis := LPExtractingInfo(Message.lParam);
if State = ARCEXTRACT_INPROCESS then begin
if FTotalSize > 0 then begin
FWriteSize := FWriteSize + lpEis.dwWriteSize;
ProgressBar1.Position := Trunc(FWriteSize / FTotalSize * 1000 );
end ;
end ;
// 処理継続(Message.Result := 1とすれば処理中止)
// キャンセル機能を追加する場合に利用する
Message.Result := 0 ;
end ;
end ;
// -----------------------------------------------------------------------------
// 指定ディレクトリ内のファイルの合計サイズを取得
// 引数のASumSizeに合計サイズを返す
// -----------------------------------------------------------------------------
procedure TForm1.GetDirFilesSize(ADir: String ; var ASumSize: UInt64);
var
LSearchPath : string ;
LSearchRec : TSearchRec;
LFullPath : string ;
begin
LSearchPath := IncludeTrailingPathDelimiter(ADir) + '*.*' ;
if FindFirst(LSearchPath, faAnyFile, LSearchRec) = 0 then
begin
repeat
if not ((LSearchRec.Name = '..' ) or (LSearchRec.Name = '.' )) then begin
if (LSearchRec.Attr and faDirectory) = faDirectory then begin
LFullPath := IncludeTrailingPathDelimiter(ADir) + LSearchRec.Name;
// パス名を与えて自分自身を呼出(再帰処理)する
GetDirFilesSize(LFullPath, ASumSize);
end ;
ASumSize := ASumSize + LSearchRec.Size;
end ;
until FindNext(LSearchRec) <> 0 ;
FindClose(LSearchRec);
end ;
end ;
end .
本テストで使用した Tar32.dll の関数を利用するためのユニットのコードです.
前項のサンプルでは,DLL 内の Tar という関数を利用するだけでしたが,本サンプルはその他のいくつかの関数を定義して使用しています.それらは,メッセージの送信の設定と,GetOriginalSize というクラスメソッド内で使用しています.
リスト5
Tar32.dll 内の関数類を利用するクラスのユニット
copy code
unit plArchieverTAR;
interface
uses
Windows, Messages, SysUtils, Classes, Controls, Forms;
const
lpszWMARCEXTRACT = 'wm_arcextract' ;
ARCEXTRACT_BEGIN = 0 ; // 該当ファイルの処理開始
ARCEXTRACT_INPROCESS = 1 ; // 該当ファイルの展開中
ARCEXTRACT_END = 2 ; // 処理終了.関連メモリを開放
ARCEXTRACT_OPEN = 3 ; // 該当書庫の処理の開始
ARCEXTRACT_COPY = 4 ; // ワークファイルの書き戻し
M_CHECK_ALL_PATH = $00000100 ;
M_CHECK_FILENAME_ONLY = $00000200 ;
FNAME_MAX32 = 512 ;
var
WM_ARCEXTRACT : UINT;
type
HARC = HGLOBAL;
TExtractingInfo = packed record
dwFileSize : DWORD;
dwWriteSize : DWORD;
szSourceFileName : array [0 ..FNAME_MAX32] of AnsiChar;
dummy1 : array [0 ..2 ] of AnsiChar;
szDestFileName : array [0 ..FNAME_MAX32] of AnsiChar;
dummy : array [0 ..2 ] of AnsiChar;
end ;
LPEXTRACTINGINFO = ^TExtractingInfo;
TExtractingInfoEx = packed record
exinfo : TExtractingInfo;
dwCompressedSize : DWORD;
dwCRC : DWORD;
uOSType : UINT;
wRatio : WORD;
wDate : WORD;
wTime : WORD;
szAttribute : array [0 ..7 ] of AnsiChar;
szMode : array [0 ..7 ] of AnsiChar;
end ;
LPEXTRACTINGINFOEX = ^TExtractingInfoEx;
TINDIVIDUALINFO = packed record
dwOrinalSize : DWORD;
dwCompressSize : DWORD;
dwCRC : DWORD;
uFlag : UINT;
uOSType : UINT;
wRatio : WORD;
wDate : WORD;
wTime : WORD;
szFileName : array [0 ..FNAME_MAX32] of AnsiChar;
dummy : array [0 ..2 ] of AnsiChar;
szAttribute : array [0 ..7 ] of AnsiChar;
szMode : array [0 ..7 ] of AnsiChar;
end ;
LPINDIVIDUALINFO = ^TINDIVIDUALINFO;
TplArchieverTAR = class (TComponent)
private
FHandle : HWND;
protected
FDllHandle : THandle;
FArcHandle : HARC;
function Execute(Cmd: String ; var AMsg: String ): Boolean;
public
constructor Create( AOwner:TComponent ); override ;
destructor Destroy(); override ;
function Extract(SrcPath, DestPath: String ; var AMsg: String ): Boolean;
function PackFiles(SrcPath, DestPath: String ; var AMsg: String ): Boolean;
function GetOriginalSize(SrcPath: String ): UInt64;
end ;
implementation
{ TplArchieverTAR }
type
// Tar32.DLLのAPIの関数定義
TTar = function (const hWnd: HWND; szCmdLine: LPCSTR; szOutPut: LPSTR;
const dwSize: DWORD): Integer; stdcall ;
TTarOpenArchive = function (const hWindow: HWND; szFileName: LPCSTR;
const dwMode: DWORD): HARC; stdcall ;
TTarCloseArchive = function (ArcHandle: HARC): Integer; stdcall ;
TTarFindFirst = function (ArcHandle: HARC; szWildName: LPCSTR;
lpSubInfo: LPINDIVIDUALINFO): Integer; stdcall ;
TTarFindNext = function (ArcHandle: HARC; lpSubInfo: LPINDIVIDUALINFO):
Integer; stdcall ;
TTarSetOwnerWindow = function (hWindows: HWND): BOOL; stdcall ;
TTarClearOwnerWindow = function (): BOOL; stdcall ;
var
FTar : TTar;
FTarOpenArchive : TTarOpenArchive;
FTarCloseArchive : TTarCloseArchive;
FTarFindFirst : TTarFindFirst;
FTarFindNext : TTarFindNext;
FTarSetOwnerWindow : TTarSetOwnerWindow;
FTarClearOwnerWindow : TTarClearOwnerWindow;
// =============================================================================
// Create処理
// =============================================================================
constructor TplArchieverTAR.Create(AOwner: TComponent);
begin
inherited ;
FDllHandle := LoadLibrary('tar32.dll' );
if FDllHandle < HINSTANCE_ERROR then begin
FDllHandle := 0 ;
end else begin
// メッセージを登録
// このユニットを使用するプログラムでWM_ARCEXTRACTメッセージを受信する
WM_ARCEXTRACT := RegisterWindowMessage(lpszWMARCEXTRACT);
// このユニット(DLL)を使用するウィンドウのハンドル
FHandle := TWinControl(AOwner).Handle;
// DLL内の関数のアドレスを取得
@FTar := GetProcAddress(FDllHandle, 'Tar' );
@FTarOpenArchive := GetProcAddress(FDllHandle, 'TarOpenArchive' );
@FTarCloseArchive := GetProcAddress(FDllHandle, 'TarCloseArchive' );
@FTarFindFirst := GetProcAddress(FDllHandle, 'TarFindFirst' );
@FTarFindNext := GetProcAddress(FDllHandle, 'TarFindNext' );
@FTarSetOwnerWindow := GetProcAddress(FDllHandle, 'TarSetOwnerWindow' );
@FTarClearOwnerWindow := GetProcAddress(FDllHandle, 'TarClearOwnerWindow' );
// FHandleのウィンドウへのメッセージ送信処理開始
FTarSetOwnerWindow(FHandle);
end ;
end ;
// =============================================================================
// Destroy処理
// =============================================================================
destructor TplArchieverTAR.Destroy;
begin
if FDllHandle <> 0 then begin
// メッセージ送信処理終了
FTarClearOwnerWindow;
FreeLibrary(FDllHandle);
end ;
FDllHandle := 0 ;
inherited ;
end ;
// =============================================================================
// GetOriginalSize
// 圧縮ファイル内のファイルの圧縮前の合計サイズを取得する関数
// =============================================================================
function TplArchieverTAR.GetOriginalSize(SrcPath: String ): UInt64;
var
LSrcPath : AnsiString;
LMask : AnsiString;
LInfo : TINDIVIDUALINFO;
LSize : UInt64;
begin
LSize := 0 ;
LSrcPath := AnsiString(SrcPath);
LMask := AnsiString('*.*' );
FArcHandle := FTarOpenArchive(FHandle, PAnsiChar(LSrcPath), M_CHECK_ALL_PATH);
if FArcHandle <> 0 then begin
if FTarFindFirst(FArcHandle, PAnsiChar(LMask), @LInfo) >= 0 then begin
repeat
LSize := LSize + LInfo.dwOrinalSize;
Application.ProcessMessages;
until FTarFindNext(FArcHandle, @LInfo) < 0 ;
end ;
FTarCloseArchive(FArcHandle);
end ;
Result := LSize;
end ;
// =============================================================================
// 圧縮メソッド
// SrcPath : 圧縮対象のディレクトリ名(このディレクトリ内のファイルを全て格納)
// DestPath : 圧縮後のファイル名のフルパス
//
// -----------------------------------------------------------------------------
// 圧縮の種類のコマンドオプションの例
//
// -z[N] gzip相当の圧縮.Nは圧縮レベルで1~9(デフォルトは6)
// --gzip=[N] 同上
// -B[N] bzip2相当の圧縮.Nは圧縮レベルで1~9(デフォルトルは9)
// --bzip(=[N]) 同上
// --bzip2(=[N]) 同上
// -G gzipまたはbzip2相当の圧縮のみ実行
// -J[N] xz相当の圧縮.Nは圧縮レベルで1~9(デフォルトルは6)
// --xz(=[N]) 同上
// --lzma(=[N]) lzma相当の圧縮.Nは圧縮レベルで1~9(デフォルトルは6)
// =============================================================================
function TplArchieverTAR.PackFiles(SrcPath, DestPath: String ;
var AMsg: String ): Boolean;
var
FCommand : String ;
begin
Result := False;
if FDllHandle = 0 then exit;
ForceDirectories(ExtractFileDir(DestPath));
FCommand := '-c -z --display-dialog=0 ' +
AnsiQuotedStr(DestPath, '"' ) + ' ' +
AnsiQuotedStr(IncludeTrailingPathDelimiter(SrcPath), '"' ) + ' ' +
'*.*' ;
// 引数を与えて関数を実行
Result := Execute(FCommand, AMsg);
end ;
// =============================================================================
// 解凍メソッド
// SrcPath : 解凍対象のファイルのフルパス
// DestPath : 解凍したファイルを格納するディレクトリ
// =============================================================================
function TplArchieverTAR.Extract(SrcPath, DestPath: String ;
var AMsg: String ): Boolean;
var
FCommand : String ;
begin
Result := False;
if FDllHandle = 0 then exit;
FCommand := '-x --display-dialog=0 ' +
AnsiQuotedStr(SrcPath, '"' ) + ' ' +
AnsiQuotedStr(IncludeTrailingPathDelimiter(DestPath), '"' );
// 引数を与えて関数を実行
Result := Execute(FCommand, AMsg);
end ;
// =============================================================================
// 圧縮または解凍の実行ルーチン
// 圧縮か解凍かは引数のコマンドで決まる
// =============================================================================
function TplArchieverTAR.Execute(Cmd: String ; var AMsg: String ): Boolean;
const
BUFF_SIZE = 8192 ;
var
ACommand : AnsiString;
Output : array [0 ..BUFF_SIZE-1 ] of AnsiChar;
begin
Result := False;
if @FTar <> nil then begin
FillChar(Output, SizeOf(Output), 0 );
// ヒントや警告が表示されるので明示的にキャストしておく
ACommand := AnsiString(Cmd);
try
// 実際にDLL内の関数を実行する部分
// tar32.dll内のTarという関数を実行
FTar(FHandle, PAnsiChar(ACommand), OutPut, BUFF_SIZE);
Result := True;
except
end ;
end ;
AMsg := String (OutPut);
end ;
end .
04_ Tar32.dll がシステムに登録されている場合
DLL がシステムに登録されているか,EXE と同じフォルダ内に存在する場合は,LoadLibrary で DLL を読み込まなくても利用できます.また,利用する関数がその DLL 内に確実に存在することが分かっている場合,関数の存在をチェックする必要もありません.
筆者の環境には Tar32.dll が登録されています.したがって,最初のサンプルプログラムを次のように変更しても動作します.これを DLL の静的リンクとも言います.
この方法は,Delphi で直接使用できない Windows API を使用する方法と同じです.つまり,Windows が提供している DLL 内の関数を使用する方法と同じです.
リスト6
Tar32.dll がシステムに登録されている場合
DLL が確実にシステムに存在して,利用する関数も DLL 内に確実に存在する場合
copy code
implementation
{$R *.dfm}
function Tar(const hWnd: HWND; szCmdLine: LPCSTR; szOutPut: LPSTR;
constdwSize: DWORD): Integer; stdcall ; external 'tar32.dll' ;
// TForm1.Button1Clickのコードは同じなので省略
// -----------------------------------------------------------------------------
// tar32.dll内のTarという関数を使用して書庫を解凍する
// -----------------------------------------------------------------------------
function TForm1.ExtractTar(SrcPath, DestPath: String ;
var AMsg: String ): Boolean;
const
BUFF_SIZE = 8192 ;
var
Command : AnsiString;
Output : array [0 ..BUFF_SIZE-1 ] of AnsiChar;
begin
Result := False;
// ヒントや警告が表示されるので明示的にキャストしておく
Command := AnsiString('-x --display-dialog=0 ' +
AnsiQuotedStr(SrcPath, '"' ) + ' ' +
AnsiQuotedStr(IncludeTrailingPathDelimiter(DestPath), '"' ));
FillChar(Output, SizeOf(Output), 0 );
try
// 実際にDLL内の関数を実行する部分
Tar(Handle, PAnsiChar(Command), OutPut, BUFF_SIZE);
AMsg := String (OutPut);
Result := True;
except
end ;
end ;
end .
05_ Tar32.dll と総合アーカイバプロジェクト
Tar32.dll は,総合アーカイバプロジェクトの仕様に準拠した DLL です.
現在のようにインターネットが普及する前は,パソコン通信がコミュニケーションの手段として利用されていました.ニフティ株式会社が運営していたパソコン通信サービスのコミュニティの場で生まれたのが総合アーカイバプロジェクトです.
異なるアーカイバでも API を可能な限り統一して,アプリケーションから容易にアーカイブファイルの操作を可能にすることを目的としたプロジェクトです.
多くの開発者がこの主旨に賛同し,多くの DLL が提供されてきました.そして,多くの圧縮・解凍ツールがこれらの DLL を使用しています.DLL は各種のプログラム言語から共通に使用することを目的にしたライブラリです.DLL で提供されていれば Delphi からも利用可能です.もちろん,Delphi に限らず,DLL 内の関数を使用するための定義 (ヘッダファイル等の作成) は必要です.
総合アーカイバプロジェクトで提供さてれいる DLL は,32 ビット版です.Unicode には対応していない DLL もあります.Unicode に対応していない DLL ではファイル名にユニコードな文字は使用できません.本ページのサンプルプログラムで使用した Tar32.dll のバージョンは,Unicode には対応していませんが,UTF-8, UTF-8-MAC, 日本語 EUC の自動変換に対応しています.
一部ですが,64 ビット版の DLL も公開されているようです.