ColdFusion 8 より追加されている<cfzip>タグは、標準の java.util.zip が使われていますが、このライブラリはパスワード付きZIPファイルの操作を行うことができないことと、ファイル名に日本語が含まれている場合に、文字コードをUTF-8で固定して処理を行います。そのため、<cfzip>タグを使ってファイルの圧縮や解凍などを行うと、Windows環境では文字化けを起こす結果となります。標準のライブラリでは行えない処理に対して、Zip4Jを使った例を紹介します。
ColdFusion 実験室で公開している情報は、ColdFusionの標準の機能では無いため動作の保証外(未サポート)となります。下記の事項も含めてそれらを予めご認識頂いた上で、参考にされるかどうかをご判断下さい。
Zip4jConstants.java と ZipParameters.java の設定項目とメソッドを確認
http://grepcode.com/file/repo1.maven.org/maven2/net.lingala.zip4j/zip4j/1.3.1/net/lingala/zip4j/util/Zip4jConstants.java
http://grepcode.com/file/repo1.maven.org/maven2/net.lingala.zip4j/zip4j/1.3.1/net/lingala/zip4j/model/ZipParameters.java
このサンプルでは、Zip4JライブラリからZipFile、Zip4jConstants、ZipParametersクラスのインスタンスを作成して、所定のメソッドを実行してzipファイルを作成しています。初期値として、SourceDir(圧縮するフォルダ)、zipFileName(zipファイルの保存先)、zipPassword(パスワード)を指定して下さい。パスワードに値が指定されている場合はパスワードをセットするメソッドも実行します。また、圧縮するファイルに日本語のファイル名が含まれている場合は、ファイル名に対するエンコードを setFileNameCharsetメソッドで指定して、Windows-31J(日本語Shift_JIS)を指定することで Windows環境でファイルの文字化けを防ぐことができます。
<cfscript> //圧縮するフォルダを指定 SourceDir="c:\temp"; //圧縮したZIPファイルの置き場所を指定 zipFileName=ExpandPath('./out/zippedFiles.zip'); //ZIPファイルにパスワードを掛ける場合はパスワードを指定(指定しない場合は"") zipPassword="test123"; zipFile = createObject("java", "net.lingala.zip4j.core.ZipFile").init(zipFileName); zipFile.setFileNameCharset("Windows-31J"); zipConstants = createObject("java", "net.lingala.zip4j.util.Zip4jConstants"); zipParameters = createObject("java", "net.lingala.zip4j.model.ZipParameters"); //圧縮率 zipParameters.setCompressionMethod(zipConstants.COMP_DEFLATE); zipParameters.setCompressionLevel(zipConstants.DEFLATE_LEVEL_NORMAL); //パスワードが空白でない場合は、パスワードをセットする if(zipPassword IS NOT ""){ zipParameters.setEncryptFiles(true); zipParameters.setEncryptionMethod(zipConstants.ENC_METHOD_STANDARD); zipParameters.setPassword(zipPassword); } //圧縮の実行 zipFile.addFolder(SourceDir, zipParameters); </cfscript>
各クラスにどのようなメソッドがあるかを参照したい場合は、上記の参照サイト(grepcode.com)の内容を参考にするか、または<cfdump>やWriteDump()でオブジェクトを指定して確認下さい。
例:<cfdump var="#zipFile#">
このサンプルでは、ZIPファイル内のファイルリストを表示します。対象のZIPファイルのパス・ファイル名を変数にセットし、その値を使ってZipFileのインスタンスを作成します。getFileHeaders()メソッドの結果はColdFusion配列に格納されますので、その後は配列に対するループを行い、getFileName()メソッドでファイル名を取得して表示します。
<cfscript> //対象のZIPファイルのファイル・パスを指定 zipFilePath = ExpandPath('./out/zippedFiles.zip'); zipFile = createObject('java', 'net.lingala.zip4j.core.ZipFile').init(zipFilePath); zipFile.setFileNameCharset("Windows-31J"); //ファイルヘッダを取得する(ファイル一覧は配列データ) aFileHeaders=zipFile.getFileHeaders(); //配列をループし、ファイル名を表示する for(i=1; i LTE ArrayLen(aFileHeaders); i=i+1) { if(not aFileHeaders[i].isDirectory()){ writeOutput(aFileHeaders[i].getFileName() & "<br>"); } } </cfscript>
このサンプルでは、該当するZIPファイルを解凍します。ZipFileライブラリのisEncrypted()メソッドで、ZIPファイルにパスワードが掛かっている場合は、setPassword()でパスワードを指定しています。誤ったパスワードを指定していると、解凍時(exactAll()メソッド実行時)にエラーが発生するため、サンプルには例外処理を含めています。
<cfscript> //対象のZIPファイルのファイル・パスを指定 zipFilePath = ExpandPath('./out/zippedFiles.zip'); //解凍先のフォルダを指定 destPath = ExpandPath('./out/'); //ZIPファイルの解除用パスワードを指定(パスワードが掛かっていない場合は"") zipPassword = "test123"; zipFile = createObject('java', 'net.lingala.zip4j.core.ZipFile').init(zipFilePath); zipFile.setFileNameCharset("Windows-31J"); if(zipFile.isEncrypted()){ zipFile.setPassword(zipPassword); } try { zipFile.extractAll(destPath); } catch(any excpt) { writeOutput("ファイルの解凍に失敗しました。パスワードが間違っているかもしれません。<br>"); writeOutput("エラーメッセージ:" & excpt.message); } </cfscript>
今回の実験室はいかがだったでしょうか?上記では該当する処理の部分のみを紹介していますが、処理をUDFやCFCにまとめて色々なページから呼び出すなども効果的かと思います。
ColdFusionはJavaをベースとしたアプリケーションのため、JavaライブラリとColdFusionとの組み合わせが可能なものであれば、既存の機能で足りない部分を補う効果が期待できます。
ただし、Javaライブラリとの組み合わせで動かせる範囲に制限があったり、そもそもまともに動かなかったりするものもあると思います。主に海外の情報となりますがColdFusionとJavaライブラリを組み合わせた色々な情報が掲載されていますので、それらの情報もぜひ参考にして下さい。