Zipファイルをすべて解凍するのではなく、中身を検索して「特定のファイル1つだけ」を取り出したい場合があります。
ZipArchiveEntry クラスの ExtractToFile メソッドを使用すると、取得したエントリ(ファイル情報)を直接指定したパスにファイルとして書き出すことができます。
目次
実装サンプル:ログアーカイブからの特定ログ抽出
以下のコードでは、Zipファイル(Logs.zip)の中から、特定のエラーログファイル(Error_2025.txt)を探し出し、それだけを解凍して取り出す処理を実装しています。
サンプルコード
using System;
using System.IO;
using System.IO.Compression; // 参照設定が必要な場合があります
public class Program
{
public static void Main()
{
string zipPath = "Logs.zip";
// Zip内のファイルパス(フォルダ階層がある場合は "logs/error.txt" のように指定)
string targetEntryName = "Error_2025.txt";
// 解凍後のファイル名
string outputPath = "Extracted_ErrorLog.txt";
// 1. テスト環境の準備 (Zipファイルの作成)
if (File.Exists(zipPath)) File.Delete(zipPath);
using (var archive = ZipFile.Open(zipPath, ZipArchiveMode.Create))
{
archive.CreateEntryFromFile(CreateDummyFile("System.log"), "System.log");
archive.CreateEntryFromFile(CreateDummyFile("Error_2025.txt"), targetEntryName);
}
try
{
// 2. Zipファイルを読み取りモードで開く
using (ZipArchive archive = ZipFile.OpenRead(zipPath))
{
// 3. 指定した名前のエントリを取得する
ZipArchiveEntry entry = archive.GetEntry(targetEntryName);
if (entry != null)
{
Console.WriteLine($"ファイルが見つかりました。サイズ: {entry.Length} bytes");
// 4. ファイルとして抽出(保存)する
// 第2引数 overwrite: true で上書きを許可
entry.ExtractToFile(outputPath, overwrite: true);
Console.WriteLine($"抽出完了: {Path.GetFullPath(outputPath)}");
}
else
{
Console.WriteLine($"エラー: {targetEntryName} はアーカイブ内に存在しません。");
}
}
}
catch (Exception ex)
{
Console.WriteLine("エラーが発生しました: " + ex.Message);
}
}
// ダミーファイル作成用ヘルパー
static string CreateDummyFile(string name)
{
File.WriteAllText(name, "Log content...");
return name;
}
}
実行結果
ファイルが見つかりました。サイズ: 14 bytes
抽出完了: C:\Work\Extracted_ErrorLog.txt
解説と技術的なポイント
1. ZipArchiveEntry.ExtractToFile
このメソッドは、エントリの内容を指定したパスにファイルとして書き出します。 ストリームを開いて CopyTo などでデータを移し替える処理を自前で書く必要がなく、非常に簡潔に実装できます。
// (従来の手法) ストリームを使う場合
// using (var reader = entry.Open())
// using (var writer = File.OpenWrite(outputPath))
// {
// reader.CopyTo(writer);
// }
// (推奨) ExtractToFileを使う場合
entry.ExtractToFile(outputPath, overwrite: true);
2. エントリの検索 (GetEntry)
archive.GetEntry("パス") は、大文字小文字を区別して完全一致するエントリを探します。 もし、大文字小文字を無視して探したい場合(例: readme.txt でも README.TXT でもヒットさせたい場合)は、archive.Entries に対して LINQ を使って検索する必要があります。
// 大文字小文字を無視して検索する例
var entry = archive.Entries.FirstOrDefault(e =>
e.FullName.Equals(targetEntryName, StringComparison.OrdinalIgnoreCase));
