Zip
はじめに
「見た目は JavaScript、頭脳(中身)は Ruby、(安定感は AC/DC)」 でお届けしているスクリプト言語 Kinx。言語はライブラリが命。ということでライブラリの使い方編。
今回は Zip です。
- 参考
- 最初の動機 ... スクリプト言語 KINX(ご紹介)
- 個別記事へのリンクは全てここに集約してあります。
- リポジトリ ... https://github.com/Kray-G/kinx
- Pull Request 等お待ちしております。
- 最初の動機 ... スクリプト言語 KINX(ご紹介)
アプリ作る時に Zip 機能は欠かせないですね。あと、脆弱だ、脆弱だ、言われてますけど、業務アプリの中ではパスワード付き Zip が(建前上)求められることも事実。なので、パスワード付き Zip が作れないと実用にならない(日本では...?)。
Zip
Zip アーカイブ作成
Zip インスタンスの作成(class Zip
)
基本的にはこんな感じ。
var zip = new Zip("zipfile.zip", File.READ|File.WRITE);
ファイル名とモードを指定する。
モード
モード | 意味 | 動作概要 |
---|---|---|
File.READ |
読み込みモード | 単独で指定した場合、ファイルが存在しなければ ZipException
|
File.WRITE |
書き込みモード | ファイルが存在しても新規に作成しなおすモード |
File.APPEND |
追記モード | ファイルが存在した場合、そのファイルに追記するモード |
File と同じ。
メソッド
Zip インスタンスのメソッドは以下の通り。
メソッド | 内容 | オプション |
---|---|---|
extract(name, [opts]) |
展開して文字列で取得 | { password, overwrite, skip, } |
extractTo(name, file [, opts]) |
ファイルに展開 | (同上) |
find(name) |
エントリを検索、エントリ・オブジェクトを返す | |
addFile(filename [, opts]) |
Zip ファイルにエントリを追加 | { password, method, aes, level } |
addString(text [, opts]) |
Zip ファイルにエントリを追加 | (同上) |
setPassword(password) |
全 Zip エントリで共通して使用するパスワードを設定 | |
setOverwrite(truefalse) |
上書き設定を一括で指定しておくために使用する |
エントリの追加(addFile()
/addString()
)
addFile()
または addString()
を使います。即座にエントリが追加される。
zip.addFile("README.md");
ファイルにディレクトリ名を与えた場合、ディレクトリは以下のファイルが追加される。また、第 2 引数にオプションを渡せる。オプションの内容は次の通り。
-
password
: パスワード付き Zip のパスワード。デフォルトは無し。 -
method
: 圧縮方法。デフォルトはdeflate
。その他、指定できるのは"store"
、"bzip2"
、"lzma"
。 -
aes
: WinZIP 互換の AES 暗号化を有効にするか(true/false)。デフォルト false。尚、addString
の場合には無視される。 -
level
: 圧縮レベル。0-9。
オプションを付ける例は以下の通り。
zip.addFile("README.md", {
method: "bzip2",
password: "password",
aes: true,
});
zip.addString("test/test1.txt", {
content: "test/test\n",
// aes: true, // addString では無視される.
});
パスワードは、展開の際に個別に指定するようにすればエントリごとに別々につけることもできる。
暗号化
addFile()
の際にオプションで指定できるが、一括で最初に設定して置く場合は setPassword()
を使うことができる。
var zip = new Zip("zipfile.zip", File.READ|File.WRITE);
zip.setPassword("password");
Zip ファイル一覧の表示
zip
インスタンスには既に配列としてエントリ・オブジェクトが格納されている。以下のようにすると一覧表示することができる。尚、zip.totalFiles
にエントリ数が格納されている。
var zip = new Zip("zipfile.zip", File.READ);
System.println("totalFiles = ", zip.totalFiles);
zip.each(function(e) {
System.println("%s:" % e.filename);
e.keySet().each(&(key) => {
if (e[key].isFunction || e[key].isObject || e[key].isUndefined) {
return; // 展開系の関数などはスキップ。
}
if (key == "crc32") { // CRC は 16 進表示
System.println(" %-14s = %10X" % key % e[key]);
} else if (key != "time" && key != "filename") { // 別で表示
System.println(" %-14s = %10d" % key % e[key]);
}
});
// time はさらにオブジェクト構造になっている
e.time.keySet().each(&(k) => {
System.println(" time.%-7d = %10d" % k % e.time[k]);
});
// // エントリを個別に展開することも可能。
// if (e.filename == "README.md") {
// e.extractTo("READMEXX.md", { password: "text", overwrite: true });
// }
});
以下のような感じで表示される。
totalFiles = 4
README.md:
compsize = 4413
size = 11621
isDirectory = 0
crc32 = EFD9A09C
isEncrypted = 1
method = deflate
time.month = 3
time.minute = 1
time.day = 19
time.year = 2020
time.second = 2
time.hour = 16
...
展開
Zip ファイルの展開は、以下の 2 通りの方法が可能。
- 直接 Zip インスタンスから展開する。
- Zip エントリオブジェクトから展開する。
Zip エントリから展開する場合は個別の展開になる。その場合、上記のようにイテレートして選択する方法と、find
メソッドを使う方法の 2 種類がある。find
メソッドは、指定したファイル名のエントリがあれば Zip エントリオブジェクトを返す。
展開時のオプションの意味は、以下の通り。
-
password
: 展開に使うパスワード。指定されなかった場合、setPassword()
で設定されたものを使う。setPassword()
でも設定されてなかった場合、パスワードなしで展開しようとする。 -
overwrite
: true を指定し、同名ファイルが既に存在した場合、上書きする。 -
skip
: true を指定し、同名ファイルが既に存在した場合、スキップする。
尚、overwrite
も skip
も指定されずに同名ファイルが存在した場合、ZipException
例外が送出される。
すべて展開
すべて展開するには、上記イテレートしたエントリに対して extractTo
を実施する。必要なディレクトリは自動的に作成される。
zip.each(&(e) => e.extractTo("examples/zip/dst" / e.filename, { password: "text", skip: true }));
なんか説明してなかった気がするが、文字列に対して
/
オペレータを適用すると、/
で連結された文字列になる。
ファイルを指定して展開
直接 Zip インスタンスに対して extract
または extractTo
メソッドを使うことが可能。
zip.extractTo("README.md", "READMEXX.md", { password: "text", skip: true });
extract
を使用した場合、展開した内容を文字列として返す。
var text = zip.extract("README.md", { password: "text" });
現在、バイナリで取得する方法が無いのに気がついたので、追加する予定。オプションに
{ binary: true }
をつけるイメージ。プレビュー 0.5.x 以降で
{ binary: true }
をサポートしました。
Zip エントリオブジェクトの場合、エントリ名を指定する引数がなくなる。
メソッド | 内容 | オプション |
---|---|---|
extract([opts]) |
展開して文字列で取得 | { password, overwrite, skip, } |
extractTo(file [, opts]) |
ファイルに展開 | (同上) |
find
を使った例は以下の通り。
zip.find("README.md")
.extractTo("READMEXX.md", { password: "text", skip: true });
var text = zip.find("README.md")
.extract({ password: "text" });
その他
使っているライブラリ
これです。
機能一覧。全然 Mini な感じがしないですね。
- Features
- Creating and extracting zip archives.
- Adding and removing entries from zip archives.
- Read and write raw zip entry data.
- Reading and writing zip archives from memory.
- Zlib, BZIP2, and LZMA compression methods.
- Password protection through Traditional PKWARE and WinZIP AES encryption.
- Buffered streaming for improved I/O performance.
- NTFS timestamp support for UTC last modified, last accessed, and creation dates.
- Disk split support for splitting zip archives into multiple files.
- Preservation of file attributes across file systems.
- Follow and store symbolic links.
- Unicode filename support through UTF-8 encoding.
- Legacy character encoding support CP437, CP932, CP936, CP950.
- Turn off compilation of compression, decompression, or encryption.
- Windows (Win32 & WinRT), macOS and Linux platform support.
- Streaming interface for easy implementation of additional platforms.
- Support for Apple's compression library ZLIB implementation.
- Zero out local file header information.
- Zip/unzip of central directory to reduce size.
- Ability to generate and verify CMS signature for each entry.
- Recover the central directory if it is corrupt or missing.
- Example minizip command line tool.
Zip64 対応
Zip64 も対応されている模様。4G 超えもいけるとの話だがテストできていない。
おわりに
Zip/Unzip はスクリプト言語を使う目的としては上位に来る機能でしょう。間違っても C で組みたいとは思わないし、簡単に Zip ファイル作りたい。
では、また次回。