Archive for the ‘File’ Category
さて、今までZipの圧縮・解凍ツールを作っていた。
もともと、世の中のツールのように高機能なZipの圧縮・解凍がしたいわけではなく
最近のZipパッケージ形式のファイル(MS-OfficeのOpenXML等)の中身を見て、
中身を変更しようかなと思ったのだが、ちょっとすんなりとはできなそうです。
しかし、結構世の中に普及しているZipファイルというのは多様なのだと学びました。
まず、Zipファイル自体のフォーマット(つまりファイルを格納するための情報の持ち方)にも、
ZipとZip64というものがあり、Zip64は大きなファイル形式も格納できるフォーマットです。
また、圧縮方法もZipの仕様としてはいろいろな圧縮ルールが入れられるのですが、事実上 deflateのみ。
ただし、deflateにも通常のdeflateとdeflate64という、これまた大きなファイルでも圧縮できる方式があるのです。
そして、ByteArray.uncompress()で確実に解凍できるのは、
Zip形式のdeflateのみなのです。
まず、macの標準ツールでZip圧縮すると、圧縮方式がdeflate64という形式になり解凍できない。
また、MS-OfficeのOpenXMLのファイルはZip64という形式のZipファイルで、これが部分的に解凍できない。
なぜか、
docProps/app.xml
docProps/core.xml
が解凍できないのです。
今のところOpenOfficeで作成したファイルは大丈夫そうです。
んー、こうなると道は2つ。
1)自前で解凍するロジックを作る
解凍が十分早くできるのか心配・・・
解凍するための資料を見ようと本を探すと、絶版ばかりで高騰中・・・・、んー大学中にハフマンなんちゃら、ちゃんと勉強しとけばよかったかな。
でも、当時はそれが何を意味するのかまったくわからなかったし。
2)ActionScriptで解凍しない
100%ローカルでできなくなるかな・・・・
になりました。
ながーい時間をかけて1)で行こうかなと思っていますが、とりあえずこのあたりは保留にしておきます。
前回、zipの展開方法を記述しましたので、今度は圧縮方法です。
例の如く、実際の圧縮には ByteArray.compress() を用いています。
基本的に、動作の確認はWindowsでしかやっておりません。
ただし、作成したzipファイルがLinuxでのunzipコマンドで展開できることは確認しております。
Zipの圧縮方法
import com.coltware.commons.zip.*;
import flash.filesystem.*;
public function zip():void{
zipWriter = new ZipFileWriter();
zfile = File.desktopDirectory.resolvePath("sample.zip");
var file1:File = File.desktopDirectory.resolvePath("sample.doc");
zipWriter.addFile(file1,"sample.doc");
// 空のディレクトリを追加する場合には、以下のようにする
// 空でない場合は、直接下のファイルのようにしてしまえば問題ありません。
zipWriter.addDirectory("フォルダ1");
var file2:File = File.desktopDirectory.resolvePath("sample1.doc");
zipWriter.addFile(file2,"フォルダ2/読んでください.doc");
// これを忘れないでください。ファイルとしては作成されますが、
// ここで最後の情報を記述していますので、
// おかしなファイルになってしまいます。
zipWriter.close();
}
また、パスのセパレータ( “/”ってやつ)は、OSに関係なく”/”にしてください。
これは、Zipフォーマットのルールですが。
また、ファイルの先頭に”/”をつけないでください。
Windowsでは見えなくなります。(linux unzipの場合にはワーニングがでて無視されるようです。)
Linux用にZipファイルを作成したい場合
zipWriter = new ZipFileWriter(ZipFileWriter.HOST_UNIX); // // デフォルトは ZipFileWriter.HOST_WIN です。 //
のようにしてください。
これで、日本語ファイル名がUTF-8になります。
また、ファイルのパーミッションを設定したい場合には、
// ディレクトリのモード(空のディレクトリを追加した場合)
zipWriter.setDirMode("0777");
// ファイルのモード
zipWriter.setFileMode("0777");
のように設定してください。
ここは文字列の8進数で設定してください。
設定後、すべてこのパーミッションが適用されます。
ファイルからではなくByteArrayデータから登録したい
public function addBytes(data:ByteArray,filename:String,bytes:ByteArray,date:Date = null):void
というメソッドがありますので、こちらを利用ください。
実際にaddFileも、この関数を使っています。
date は、最終変更日時ですが、何も入れなければ”今”の時間が入ります。
これを書いていて、Zipの展開には非同期処理があるのですが、圧縮には非同期処理をつけ忘れたことに気が付きました。
Fzipとの違い
- 日本語ファイルの対応
MACでZipしたファイルをWinで解凍すると文字化けするという問題の対応などもしてあります。
日本語環境で、Windowsで作られたと思われるZipファイルはSJIS, それ以外はUTF-8がファイル名の文字コードになります。
ただし、書き込み時には作成されるホストOSを選ぶようにします。
文字コード以外にも、考慮する部分が出てきますので・・・ - 読み込み時に情報レコードから先に読み大きなファイルでも少ない時間で情報を取得
ファイルを最後から読んでいます。
まあ、このあたりはAIRだからこそできるわけですが・・・・
ActionScriptってファイルの読み込みが遅いんですよね。 - ファイルの属性対応
いわゆる、そのファイルがディレクトリか、ファイルかなど。また、UNIX系の場合にはパーミッションなど。
このあたりが設定されていないと、うまく解凍できないものもありますので・・・ - 非同期対応
解凍していると、固まってしまうのですがこれを回避しています。
ただし、圧縮ではありません。(ただ忘れただけですので作ります)
ダウンロードは前回の記事を見てください。
AIRでzipファイルの圧縮と展開(解凍)できるライブラリを公開します。
使い方
読み込み方法
import com.coltware.commons.zip.ZipEntry;
import com.coltware.commons.zip.ZipEvent;
import com.coltware.commons.zip.ZipFileReader;
private function unzip(file:File):void{
var zipReader:ZipFileReader = new ZipFileReader();
zipReader.open(file); <- Fileオブジェクトを設定してください
var entries:Array = zipReader.getEntries();
for(var i:int = 0; i<entries.length; i++){
var entry:ZipEntry = entries[i] as ZipEntry;
var filename:String = entry.getFilename();
var bytes:ByteArray = zipReader.unzip(entry);
// ここで、ByteArrayのデータをファイル等に書き出してください。
// getFilename() は、文字コードを自動的にSJISもしくはUTF-8を判別します。
// MACの濁点も解決します。
// ただし、展開処理で bytearray.uncompress(...) を使っているだけなので、なぜか解凍が失敗するものもあります。
}
ってのがおおよその、展開方法です。
zipReader.addEventListener(ZipEvent.ZIP_DATA_UNCOMPRESS,uncompressData); zipReader.unzipAsync(entry);
とすれば、非同期で展開が行われます。
private function uncompressData(e:ZipEvent):void{
var entry:ZipEntry = e.entry;
var file:File = dir.resolvePath(entry.getFilename());
var fs:FileStream = new FileStream();
fs.open(file,FileMode.WRITE);
fs.writeBytes(e.data);
fs.close();
}
のようにしてZipEntryとdata(ByteArray)で操作が行えます。
次回は、書き込みの方法も紹介します。
いま、ソースにコメントを書き込み中・・・・
asdocもできたらドキュメントともにソースも公開したいと思います。

