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との違い

  1. 日本語ファイルの対応
    MACでZipしたファイルをWinで解凍すると文字化けするという問題の対応などもしてあります。
    日本語環境で、Windowsで作られたと思われるZipファイルはSJIS, それ以外はUTF-8がファイル名の文字コードになります。
    ただし、書き込み時には作成されるホストOSを選ぶようにします。
    文字コード以外にも、考慮する部分が出てきますので・・・
  2. 読み込み時に情報レコードから先に読み大きなファイルでも少ない時間で情報を取得
    ファイルを最後から読んでいます。
    まあ、このあたりはAIRだからこそできるわけですが・・・・
    ActionScriptってファイルの読み込みが遅いんですよね。
  3. ファイルの属性対応
    いわゆる、そのファイルがディレクトリか、ファイルかなど。また、UNIX系の場合にはパーミッションなど。
    このあたりが設定されていないと、うまく解凍できないものもありますので・・・
  4. 非同期対応
    解凍していると、固まってしまうのですがこれを回避しています。
    ただし、圧縮ではありません。(ただ忘れただけですので作ります)

ダウンロードは前回の記事を見てください。

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もできたらドキュメントともにソースも公開したいと思います。

RSS
Add to Google

カスタム検索
ソフトウェア&ライブラリ


ライブラリ
airxmail(en)
AIR版メール送受信ライブラリ
airxzip
AIR版ZIP圧縮・解凍ライブラリ
カレンダー
2010年9月
« 8月    
 12345
6789101112
13141516171819
20212223242526
27282930  
アーカイブ
にほんブログ村 IT技術ブログへ