このチュートリアルでは、個々のファイルを圧縮および展開する方法について説明します。これらは zip ファイルではなく、ディスク上の圧縮ストリームが対象であることに注意してください。Zip ファイルについては、「Zip ファイルの操作」チュートリアルで扱います。最終アプリケーションは、次の図のように表示されます。
新しい Visual Studio プロジェクトを開始し、ツールボックスからフォームに次のコントロールを追加します。
| ボタン | Button.Text プロパティ | Button.Name プロパティ | Button.Enabled プロパティ |
|---|---|---|---|
| 1 | ファイルの圧縮 | btnCompress | True(デフォルト) |
| 2 | ファイルの展開 | btnExpand | False |
[ファイルの展開]ボタンは、展開する圧縮データがある場合にのみ使用できます。
ソリューションエクスプローラウィンドウに移動し、[すべてのファイルを表示]ボタンをクリックします。[参照]を右クリックし、[参照の追加]メニューオプションを選択します。リストから C1.C1Zip アセンブリを選択するか、ファイルを参照して C1.C1Zip.2.dll ファイルを探します。
[Form1.vb]タブ(C# では[Form1.cs]タブ)を選択するか、[表示]→[コード]を選択して、コードエディタを開きます。ファイルの上部に、次のステートメントを追加します。
Visual Basic でコードを書く場合
| Visual Basic |
コードのコピー
|
|---|---|
Imports System.IO Imports C1.C1Zip |
|
C# でコードを書く場合
| C# |
コードのコピー
|
|---|---|
using System.IO; using C1.C1Zip; |
|
これで、C1Zip アセンブリと System.IO アセンブリで定義されているオブジェクトがプロジェクトから可視になり、タイピング量を大きく減らすことができます。
フォームのコードエディタで、次の定数を定義します。
Visual Basic でコードを書く場合
| Visual Basic |
コードのコピー
|
|---|---|
Private Const DIR_COMP = "\compressed" Private Const DIR_EXP = "\expanded" |
|
C# でコードを書く場合
| C# |
コードのコピー
|
|---|---|
private const string DIR_COMP = @"\compressed"; private const string DIR_EXP = @"\expanded"; |
|
これらは、圧縮ファイルと展開後ファイルを保存するディレクトリの名前です(ディスク上のチュートリアルアプリケーションが配置されているディレクトリからの相対ディレクトリ)。
[ファイルの圧縮]コマンドボタンの Click イベントを処理する次のコードを追加します。
Visual Basic でコードを書く場合
| Visual Basic |
コードのコピー
|
|---|---|
Private Sub btnCompress_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCompress.Click
' アプリケーションディレクトリを取得します。
Dim appPath As String = Application.ExecutablePath
Dim i As Integer = appPath.IndexOf("\bin\")
If i > 0 Then appPath = appPath.Substring(0, i)
' 圧縮ファイルのディレクトリを作成します。
If (Directory.Exists(appPath + DIR_COMP)) Then
Directory.Delete(appPath + DIR_COMP, True)
End If
Directory.CreateDirectory(appPath + DIR_COMP)
' 圧縮統計値を収集する準備をします。
Dim count As Long
Dim size As Long
Dim sizeCompressed As Long
Dim ticks As Long = DateTime.Now.Ticks
' アプリケーションディレクトリにあるすべてのファイルを圧縮ディレクトリに圧縮します。
Dim files As String() = Directory.GetFiles(appPath)
Dim srcFile As String
For Each srcFile In files
Dim dstFile As String
dstFile = appPath + DIR_COMP + "\" + Path.GetFileName(srcFile) + ".cmp"
' ファイルを圧縮します。
CompressFile(dstFile, srcFile)
' 統計値を更新します。
count = count + 1
size = size + New FileInfo(srcFile).Length
sizeCompressed = sizeCompressed + New FileInfo(dstFile).Length
Next srcFile
' 統計値を表示します。
Dim msg As String = String.Format("Compressed {0} files in {1} ms." & vbCrLf & "Original size: {2:#,###}" & vbCrLf & "Compressed size: {3:#,###} ({4:0.00}% of original)", count, (DateTime.Now.Ticks - ticks) / TimeSpan.TicksPerMillisecond, size, sizeCompressed, (sizeCompressed / size) * 100.0)
Label1.Text = msg
' これで、展開することができます。
btnExpand.Enabled = True
End Sub
|
|
C# でコードを書く場合
| C# |
コードのコピー
|
|---|---|
private void btnCompress_Click(object sender, EventArgs e)
{
// アプリケーションディレクトリを取得します。
string appPath = Application.ExecutablePath;
int i = appPath.IndexOf(@"\bin\");
if (i > 0) appPath = appPath.Substring(0, i);
// 圧縮ファイルのディレクトリを作成します。
if ((Directory.Exists(appPath + DIR_COMP)))
Directory.Delete(appPath + DIR_COMP, true);
Directory.CreateDirectory(appPath + DIR_COMP);
// 圧縮統計値を収集する準備をします。
long count = 0;
long size = 0;
long sizeCompressed = 0;
long ticks = DateTime.Now.Ticks;
// アプリケーションディレクトリにあるすべてのファイルを圧縮ディレクトリに圧縮します。
foreach (string srcFile in Directory.GetFiles(appPath))
{
string dstFile = appPath + DIR_COMP + @"\" + Path.GetFileName(srcFile) + ".cmp";
// ファイルを圧縮します。
CompressFile(dstFile, srcFile);
// 統計値を更新します。
count++;
size += new FileInfo(srcFile).Length;
sizeCompressed += new FileInfo(dstFile).Length;
}
// 統計値を表示します。
string msg = string .Format("Compressed {0} files in {1} ms.\n\r" + "Original size: {2:#,###}\n\r" + "Compressed size: {3:#,###} ({4:0.00}% of original)", count, (DateTime.Now.Ticks - ticks) / TimeSpan.TicksPerMillisecond, size, sizeCompressed, (sizeCompressed / size) * 100.0);
label1.Text = msg;
// これで、展開することができます。
btnExpand.Enabled = true;
}
|
|
重要な行は、ユーティリティ関数 CompressFile の呼び出しです。ここで、選択されたファイルをそれぞれ圧縮します。圧縮ファイルは、アプリケーションフォルダにある \compressed ディレクトリに保存されます。ファイル名は、元のファイルの名前に拡張子 CMP が付加された名前になります。
次のように CompressFile 関数のコードを追加します。
Visual Basic でコードを書く場合
| Visual Basic |
コードのコピー
|
|---|---|
Private Function CompressFile( dstFile As String, srcFile As String) As Boolean
' ファイルを圧縮する準備をします。
Dim retval As Boolean = True
Dim srcStream As FileStream = Nothing
Dim dstStream As FileStream = Nothing
Try
' ファイルを開きます。
srcStream = New FileStream(srcFile, FileMode.Open, FileAccess.Read)
dstStream = New FileStream(dstFile, FileMode.Create, FileAccess.Write)
' 書き込み先のファイルの圧縮プログラムストリームを開きます。
Dim sw As C1ZStreamWriter = New C1ZStreamWriter(dstStream)
' ソースを圧縮プログラムストリームにコピーします。
StreamCopy(sw, srcStream)
Catch
' 例外? 呼び出し元に処理が失敗したことを通知します。
retval = False
Finally
' 必ずストリームを閉じます。
If Not (srcStream Is Nothing) Then srcStream.Close()
If Not (dstStream Is Nothing) Then dstStream.Close()
End Try
' 完了。
CompressFile = False
End Function
|
|
C# でコードを書く場合
| C# |
コードのコピー
|
|---|---|
private bool CompressFile(string dstFile, string srcFile)
{
// ファイルを圧縮する準備をします。
bool retval = true;
FileStream srcStream = null;
FileStream dstStream = null;
try
{
// ファイルを開きます。
srcStream = new FileStream(srcFile, FileMode.Open, FileAccess.Read);
dstStream = new FileStream(dstFile, FileMode.Create, FileAccess.Write);
// 書き込み先のファイルの圧縮プログラムストリームを開きます。
C1ZStreamWriter sw = new C1ZStreamWriter(dstStream);
// ソースを圧縮プログラムストリームにコピーします。
StreamCopy(sw, srcStream);
}
catch
{
// 例外? 呼び出し元に処理が失敗したことを通知します。
retval = false;
}
finally
{
// 必ずストリームを閉じます。
if (srcStream != null) srcStream.Close();
if (dstStream != null) dstStream.Close();
}
// 完了。
return false;
}
|
|
この関数は、最初に新しいファイルストリームを2つ作成します。1つはソースファイル用、もう1つは圧縮ファイル用です。次に、C1ZStreamWriter オブジェクトを作成し、それを出力先ストリームにアタッチします。次に、StreamCopy 関数を呼び出して、ソースファイルからデータを転送し、圧縮プログラムストリームに書き込みます。
最後に、両方のストリームを閉じます。Finally ステートメントを使用することで、関数の実行中に例外が発生した場合でも、両方のストリームが正しく閉じられます。
StreamCopy 関数は、ストリーム間でバイトを単純にコピーします。次にコードを示します。
Visual Basic でコードを書く場合
| Visual Basic |
コードのコピー
|
|---|---|
Private Sub StreamCopy(dstStream As Stream, srcStream As Stream)
Dim buffer(32768) As Byte
Dim read As Integer
Do
read = srcStream.Read(buffer, 0, buffer.Length)
dstStream.Write(buffer, 0, read)
Loop While read > 0
dstStream.Flush()
End Sub
|
|
C# でコードを書く場合
| C# |
コードのコピー
|
|---|---|
private void StreamCopy(Stream dstStream, Stream srcStream)
{
byte[] buffer= new byte[32768];
for (;;)
{
int read = srcStream.Read(buffer, 0, buffer.Length);
if (read == 0) break;
dstStream.Write(buffer, 0, read);
}
dstStream.Flush();
}
|
|
この関数は、コピーの完了時に Flush メソッドを呼び出して、キャッシュされているデータがあればすべて書き出します。この動作は、圧縮ストリームを処理する際は特に重要です。圧縮ストリームでは、圧縮率を向上させるために大量のデータがキャッシュされるためです。
[ファイルの展開]コマンドボタンの Click イベントを処理する次のコードを追加します。
Visual Basic でコードを書く場合
| Visual Basic |
コードのコピー
|
|---|---|
Private Sub btnExpand_Click(sender As Object, e As EventArgs) Handles btnExpand.Click
' アプリケーションディレクトリを取得します。
Dim appPath As String = Application.ExecutablePath
Dim i As Integer = appPath.IndexOf("\bin\")
If i > 0 Then appPath = appPath.Substring(0, i)
' 展開後ファイルのディレクトリを作成します。
If Directory.Exists(appPath + DIR_EXP) Then
Directory.Delete(appPath + DIR_EXP, True)
End If
Directory.CreateDirectory(appPath + DIR_EXP)
' 圧縮統計値を収集する準備をします。
Dim count As Long
Dim size As Long
Dim sizeExpanded As Long
Dim ticks As Long = DateTime.Now.Ticks
' compressed ディレクトリにあるファイルをすべて expanded ディレクトリに展開します。
Dim srcFile As String
Dim files As String()
files = Directory.GetFiles(appPath + DIR_COMP)
For Each srcFile In files
' ファイルを展開します。
Dim dstFile As String = appPath + DIR_EXP + "\" + Path.GetFileName(srcFile)
dstFile = dstFile.Replace(".cmp", "")
ExpandFile(dstFile, srcFile)
' 統計値を更新します。
count = count + 1
size = size + New FileInfo(srcFile).Length
sizeExpanded = sizeExpanded + New FileInfo(dstFile).Length
Next srcFile
' 統計値を表示します。
Dim msg As String
msg = String.Format("Expanded {0} files in {1} ms." & vbCrLf & "Original size: {2:#,###}" & vbCrLf & "Expanded size: {3:#,###} ({4:0.00} x size of compressed)", count, (DateTime.Now.Ticks - ticks) / TimeSpan.TicksPerMillisecond, size, sizeExpanded, sizeExpanded / size)
Label1.Text = msg
End Sub
|
|
C# でコードを書く場合
| C# |
コードのコピー
|
|---|---|
private void btnExpand_Click(object sender, EventArgs e)
{
// アプリケーションディレクトリを取得します。
string appPath = Application.ExecutablePath;
int i = appPath.IndexOf(@"\bin\");
if (i > 0) appPath = appPath.Substring(0, i);
// 展開後ファイルのディレクトリを作成します。
if (Directory.Exists(appPath + DIR_EXP))
Directory.Delete(appPath + DIR_EXP, true);
Directory.CreateDirectory(appPath + DIR_EXP);
// 圧縮統計値を収集する準備をします。
long count = 0;
long size = 0;
long sizeExpanded = 0;
long ticks = DateTime.Now.Ticks;
// compressed ディレクトリにあるファイルをすべて expanded ディレクトリに展開します。
foreach (string srcFile in Directory.GetFiles(appPath + DIR_COMP))
{
// ファイルを展開します。
string dstFile = appPath + DIR_EXP + @"\" + Path.GetFileName(srcFile);
dstFile = dstFile.Replace(".cmp", "");
ExpandFile(dstFile, srcFile);
// 統計値を更新します。
count++;
size += new FileInfo(srcFile).Length;
sizeExpanded += new FileInfo(dstFile).Length;
}
// 統計値を表示します。
string msg = string .Format("Expanded {0} files in {1} ms.\r\n" + "Original size: {2:#,###}\r\n" + "Expanded size: {3:#,###} ({4:0.00} x size of compressed)", count, (DateTime.Now.Ticks - ticks) / TimeSpan.TicksPerMillisecond, size, sizeExpanded, sizeExpanded / size);
label1.Text = msg;
}
|
|
重要な行は、ユーティリティ関数 ExpandFile の呼び出しです。ここで、前に圧縮されたファイルを展開します。展開後ファイルは、アプリケーションフォルダにある \expanded ディレクトリに保存されます。ファイル名は、元のファイルの名前から拡張子 CMP が除去された名前になります。
次に、ExpandFile 関数のコードを示します。
Visual Basic でコードを書く場合
| Visual Basic |
コードのコピー
|
|---|---|
Private Function ExpandFile(dstFile As String, srcFile As String) As Boolean
' ファイルを展開する準備をします。
Dim retval As Boolean = True
Dim srcStream As FileStream = Nothing
Dim dstStream As FileStream = Nothing
Try
' ファイルを開きます。
srcStream = New FileStream(srcFile, FileMode.Open, FileAccess.Read)
dstStream = New FileStream(dstFile, FileMode.Create, FileAccess.Write)
' 圧縮ソースのエキスパンダストリームを開きます。
Dim sr As C1ZstreamReader = New C1ZStreamReader(srcStream)
' エキスパンダストリームを出力先のファイルにコピーします。
StreamCopy(dstStream, sr)
Catch
' 例外? 呼び出し元に処理が失敗したことを通知します。
retval = False
Finally
' 必ずストリームを閉じます。
If Not (srcStream Is Nothing) Then srcStream.Close()
If Not (dstStream Is Nothing) Then dstStream.Close()
End Try
' 完了。
ExpandFile = retval
End Sub
|
|
C# でコードを書く場合
| C# |
コードのコピー
|
|---|---|
private bool ExpandFile(string dstFile, string srcFile)
{
// ファイルを展開する準備をします。
bool retval = true;
FileStream srcStream = null;
FileStream dstStream = null;
try
{
// ファイルを開きます。
srcStream = new FileStream(srcFile, FileMode.Open, FileAccess.Read);
dstStream = new FileStream(dstFile, FileMode.Create, FileAccess.Write);
// 圧縮ソースのエキスパンダストリームを開きます。
C1ZStreamReader sr = new C1ZStreamReader(srcStream);
// エキスパンダストリームを出力先のファイルにコピーします。
StreamCopy(dstStream, sr);
}
catch
{
// 例外? 呼び出し元に処理が失敗したことを通知します。
retval = false;
}
finally
{
// 必ずストリームを閉じます。
if (srcStream != null) srcStream.Close();
if (dstStream != null) dstStream.Close();
}
// 完了。
return retval;
}
|
|
この関数は CompressFile に似ていますが、C1ZStreamWriter を出力先ストリームにアタッチする代わりに、C1ZStreamReader をソースストリームにアタッチする点が異なります。
これで「ファイルの圧縮」チュートリアルは終了です。