1. ホーム
  2. javascript

[解決済み] ファイルの解凍

2023-06-24 02:01:07

質問

表示したいのは OpenOffice ファイル、.odt と .odp をウェブブラウザを使用してクライアント側で表示したい。

これらのファイルは圧縮されたファイルです。Ajax を使用すると、サーバーからこれらのファイルを取得できますが、これらは圧縮されたファイルです。これらのファイルを解凍するには JavaScript を使って解凍する必要があるのですが、inflate.jsを使ってみました。 http://www.onicos.com/staff/iz/amuse/javascript/expert/inflate.txt を使ってみましたが、成功しませんでした。

どうすればいいのでしょうか?

どのように解決するのですか?

Javascriptで解凍ソフトを作りました。 動作します。

これは Andy G.P. Na のバイナリファイルリーダー notmasteryet のいくつかの RFC1951 inflate ロジック。 . ZipFile クラスを追加しました。

の作業例です。

http://cheeso.members.winisp.net/Unzip-Example.htm (デッドリンク)

ソースはこちら。

http://cheeso.members.winisp.net/srcview.aspx?dir=js-unzip (デッドリンク)

NB : リンクが切れています。すぐに新しいホストを探します。

ソースには ZipFile.htm のデモページと、zipfile クラス、inflate クラス、バイナリファイルリーダークラスの 3 つのスクリプトが含まれています。また、このデモは jQuery と jQuery UI に依存しています。 js-zip.zip ファイルをダウンロードすれば、必要なソースはすべてそこにあります。


アプリケーションのコードをJavascriptで書くとこんな感じです。

// In my demo, this gets attached to a click event.
// it instantiates a ZipFile, and provides a callback that is
// invoked when the zip is read.  This can take a few seconds on a
// large zip file, so it's asynchronous. 
var readFile = function(){
    $("#status").html("<br/>");
    var url= $("#urlToLoad").val();
    var doneReading = function(zip){
        extractEntries(zip);
    };

    var zipFile = new ZipFile(url, doneReading);
};


// this function extracts the entries from an instantiated zip
function extractEntries(zip){
    $('#report').accordion('destroy');

    // clear
    $("#report").html('');

    var extractCb = function(id) {
        // this callback is invoked with the entry name, and entry text
        // in my demo, the text is just injected into an accordion panel.
        return (function(entryName, entryText){
            var content = entryText.replace(new RegExp( "\\n", "g" ), "<br/>");
            $("#"+id).html(content);
            $("#status").append("extract cb, entry(" + entryName + ")  id(" + id + ")<br/>");
            $('#report').accordion('destroy');
            $('#report').accordion({collapsible:true, active:false});
        });
    }

    // for each entry in the zip, extract it. 
    for (var i=0; i<zip.entries.length;  i++) {
        var entry = zip.entries[i];

        var entryInfo = "<h4><a>" + entry.name + "</a></h4>\n<div>";

        // contrive an id for the entry, make it unique
        var randomId = "id-"+ Math.floor((Math.random() * 1000000000));

        entryInfo += "<span class='inputDiv'><h4>Content:</h4><span id='" + randomId +
            "'></span></span></div>\n";

        // insert the info for one entry as the last child within the report div
        $("#report").append(entryInfo);

        // extract asynchronously
        entry.extract(extractCb(randomId));
    }
}


このデモは2つのステップで動作します。 このデモは readFile fn はクリックによって起動され、ZipFile オブジェクトをインスタンス化し、Zip ファイルを読み取ります。読み込みが完了すると、非同期のコールバックがあります (適度な大きさの Zip ファイルであれば、通常 1 秒以内に完了します) - このデモでは、コールバックは doneReading ローカル変数に保持されており、単純に extractEntries を呼び出すだけです。 を呼び出すだけで、提供された ZIP ファイルのすべてのコンテンツをやみくもに解凍します。 実際のアプリケーションでは、おそらく抽出するエントリの一部を選択することになるでしょう (ユーザーが選択できるようにするか、プログラムによって 1 つまたは複数のエントリを選択するなど)。

extractEntries fnは全てのエントリを反復処理し、その後に extract() を呼び出し、コールバックを渡します。 エントリの解凍には時間がかかり、ZIP ファイル内の各エントリに対して 1 秒以上かかることがあります。これは、非同期が適切であることを意味します。extract コールバックは、抽出されたコンテンツをページ上の jQuery アコーディオンに追加するだけです。もしコンテンツがバイナリであれば、そのようにフォーマットされます(表示されません)。


動作はしますが、実用性はやや限定的だと思います。

EDIT : JavascriptのZipFileは、IE9とChromeで、これよりもかなり速く解凍されます。コンパイルされたプログラムよりはまだ遅いですが、通常のブラウザの使用では十分な速さです。

もうひとつは、ストリーミングを行わないことです。基本的に、ZIP ファイルのコンテンツ全体をメモリに流し込んでいます。本当のプログラミング環境では、zip ファイルのメタデータのみを読み込み (たとえば、エントリごとに 64 バイト)、必要に応じて他のデータを読み込んで解凍することができます。 私の知る限り、javascript でそのような IO を行う方法はありません。したがって、唯一の選択肢は zip 全体をメモリに読み込んで、その中でランダムアクセスを行うことです。 つまり、大きなzipファイルの場合、システムメモリに無理な要求をすることになります。小さい zip ファイルではそれほど問題ではありません。

また ZIP 暗号化、WinZip 暗号化、ZIP64 など、unzipper にわざわざ実装しなかった多くの zip オプションがあります。 UTF-8 でエンコードされたファイル名。 といった具合です。( EDIT - は UTF-8 でエンコードされたファイル名を処理するようになりました)。ZipFileクラスは基本的なことを扱いますが。これらのうちのいくつかは、実装するのが難しくないでしょう。 私は AES 暗号化クラス を持っています。これは、暗号化をサポートするために統合することができます。Zip64をサポートすることは、おそらくJavascriptのほとんどのユーザにとって無意味でしょう。なぜなら、それは>4gbのzipファイルをサポートするためのものであり、ブラウザでそれらを展開する必要はありません。

また、バイナリコンテンツを解凍する場合のテストはしていません。今はテキストを解凍しています。 もし zip されたバイナリファイルがあれば、それを適切に処理するために ZipFile クラスを編集する必要があります。私はそれをきれいに行う方法を見つけ出していません。 バイナリファイルも扱えるようになりました。


EDIT - JSのunzipライブラリとデモを更新しました。 テキストに加え、バイナリファイルを扱えるようになりました。テキストファイルを読むときに使用するエンコーディングを指定できるようになりました。 また、デモも拡張され、ブラウザで XLSX ファイルを解凍する様子などを見ることができます。

というわけで、実用性や興味は限定的だと思いますが、動作はします。Node.jsでも動くんだろうなぁ。