web-dev-qa-db-ja.com

Zipアーカイブ内の単一のファイルを読み取る方法

Zipファイル内の「test.txt」という1つのファイルの内容を読み取る必要があります。 Zipファイル全体は非常に大きなファイル(2GB)であり、多数のファイル(10,000,000)が含まれているため、全体を抽出することは私にとって実行可能なソリューションではありません。単一のファイルを読み取るにはどうすればよいですか?

35
e-info128

Zip://ラッパー

$handle = fopen('Zip://test.Zip#test.txt', 'r'); 
$result = '';
while (!feof($handle)) {
  $result .= fread($handle, 8192);
}
fclose($handle);
echo $result;

file_get_contents も:

$result = file_get_contents('Zip://test.Zip#test.txt'); 
echo $result;
54
Rocket Hazmat

@ Rocket-Hazmat fopenソリューションは、Zipファイルがパスワードで保護されている場合、fopenが失敗し、feofが常にtrueになるため、無限ループを引き起こす可能性があることに注意してください。エラーが発生します。

これをに変更したい場合があります

$handle = fopen('Zip://file.Zip#file.txt', 'r');
$result = '';
if ($handle) {
    while (!feof($handle)) {
        $result .= fread($handle, 8192);
    }
    fclose($handle);
}
echo $result;

これにより、無限ループの問題が解決しますが、Zipファイルがパスワードで保護されている場合は、次のようになります。

警告:file_get_contents(Zip://file.Zip#file.txt):ストリームを開けませんでした:操作に失敗しました

しかし解決策があります

PHP 7.2以降、暗号化されたアーカイブのサポートが追加されました。

そのため、この方法で両方を実行できますfile_get_contentsおよびfopen

$options = [
    'Zip' => [
        'password' => '1234'
    ]
];

$context = stream_context_create($options);
echo file_get_contents('Zip://file.Zip#file.txt', false, $context);

ただし、暗号化されたアーカイブを気にせずにファイルを読み取る前に、ファイルが存在するかどうかを確認するためのより良い解決策は、使用していますZipArchive

$Zip = new ZipArchive;
if ($Zip->open('file.Zip') !== TRUE) {
    exit('failed');
}
if ($Zip->locateName('file.txt') !== false) {
    echo 'File exists';
} else {
    echo 'File does not exist';
}

これは機能します(パスワードを知っている必要はありません)

注:locateNameメソッドを使用してフォルダーを見つけるには、folder/のように、末尾にスラッシュを付けて渡す必要があります。

0
Rain