001    /*
002     * Copyright (c) 2009 The openGion Project.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *     http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013     * either express or implied. See the License for the specific language
014     * governing permissions and limitations under the License.
015     */
016    package org.opengion.fukurou.util;
017    
018    import java.io.BufferedInputStream;
019    import java.io.BufferedOutputStream;
020    import java.io.File;
021    import java.io.FileInputStream;
022    import java.io.FileNotFoundException;
023    import java.io.FileOutputStream;
024    import java.io.IOException;
025    import java.util.ArrayList;
026    import java.util.List;
027    import java.util.zip.ZipEntry;
028    import java.util.zip.ZipInputStream;
029    import java.util.zip.ZipOutputStream;
030    
031    /**
032     * ZipFileUtil.java は、ZIPファイルの解凍ã?圧縮を行うためのUtilクラスですã?
033     *
034     * @og.group ユーãƒ?‚£リãƒ?‚£
035     *
036     * @version  4.1
037     * @author       Hiroki Nakamura
038     * @since    JDK5.0,
039     */
040    public final class ZipFileUtil {
041    
042            /** ファイル読み込み時ã?バッファサイズ */
043            private static final int        BUF_SIZE        = 1024;
044    
045            /**
046             * 全てスタãƒ?‚£ãƒ?‚¯メソãƒ?ƒ‰のためインスタンスの作æ?を禁止しますã?
047             */
048            private ZipFileUtil() {};
049    
050            /**
051             * 引数にæŒ?®šされたZIPファイルをフォルãƒ?�«解凍しますã?
052             * 解凍å?のファイルが存在する場合でもã?上書きされますã?で注意下さã�??
053             *
054             * @og.rev 4.1.0.2 (2008/02/01) 新規追åŠ?
055             * @og.rev 4.3.1.1 (2008/08/23) mkdirs の戻りå?判å®?
056             * @og.rev 4.3.3.3 (2008/10/22) mkdirsする前に存在チェãƒ?‚¯
057             * @og.rev 5.1.9.0 (2010/08/01) 更新時刻の設å®?
058             *
059             * @param targetPath 解凍å?のフォルãƒ?
060             * @param zipFileName 解凍するZIPファイル
061             *
062             * @return 解凍されたZIPファイルのä¸?¦§
063             */
064            public static List<String> unCompress( final String targetPath, final String zipFileName ) {
065                    // 解凍å?フォルãƒ??末尾ã�?/'又ã?'\'でなければ区åˆ?‚Šæ–?­—を挿入
066                    String tmpPrefix = targetPath;
067                    if( File.separatorChar != targetPath.charAt( targetPath.length() - 1 ) ) {
068                            tmpPrefix = tmpPrefix + File.separator;
069                    }
070    
071                    List<String> list = new ArrayList<String>();
072                    ZipInputStream zis = null;
073                    ZipEntry entry = null;
074                    BufferedOutputStream out = null;
075                    String fileName = null;
076                    File tmpFile = null;
077                    try {
078                            zis = new ZipInputStream( new BufferedInputStream( new FileInputStream( zipFileName ) ) );
079    
080                            while( ( entry = zis.getNextEntry() ) != null ) {
081                                    fileName = tmpPrefix + entry.getName().replace( '/', File.separatorChar );
082                                    list.add( fileName );
083    
084                                    boolean flag = true;    // 4.3.1.1 (2008/08/23) mkdirs の戻りå?判å®?
085                                    tmpFile = new File( fileName );
086                                    // ãƒ?‚£レクトリの場合ã?、è?身を含ã‚?ƒ‡ィレクトリを作æ?
087                                    if( entry.isDirectory() ) {
088                                            // 4.3.3.3 (2008/10/22) 作æ?する前に存在チェãƒ?‚¯
089                                            if( !tmpFile.exists() ) {
090                                                    flag = tmpFile.mkdirs();
091                                            }
092                                    }
093                                    // ãƒ?‚£レクトリの場合ã?、è?身の親となるディレクトリを作æ?
094                                    else {
095                                            // 4.3.3.3 (2008/10/22) 作æ?する前に存在チェãƒ?‚¯
096                                            if( !tmpFile.getParentFile().exists() ) {
097                                                    flag = new File( fileName ).getParentFile().mkdirs();
098                                            }
099    
100                                            out = new BufferedOutputStream( new FileOutputStream( fileName ) );
101                                            byte[] buf = new byte[BUF_SIZE];
102                                            int count = 0;
103                                            while( ( count = zis.read( buf ) ) != -1 ) {
104                                                    out.write( buf, 0, count );
105                                            }
106                                            out.close();
107                                    }
108                                    // 4.3.1.1 (2008/08/23) mkdirs の戻りå?判å®?
109                                    if( ! flag ) { System.err.println( fileName + " の ãƒ?‚£レクトリ作æ?に失敗しましたã€? ); }
110                                    // 5.1.9.0 (2010/08/01) 更新時刻の設å®?
111                                    long lastTime = entry.getTime();
112                                    if( lastTime >= 0 ) {
113                                            flag = tmpFile.setLastModified( lastTime );
114                                    }
115                                    if( ! flag ) { System.err.println( fileName + " の 更新時刻の設定に失敗しましたã€? ); }
116                            }
117                    }
118                    catch( FileNotFoundException ex ) {
119                            String errMsg = "解凍ファイルが作æ?できませんã€?ファイルå�?" + fileName + "]";
120                            throw new RuntimeException( errMsg, ex );
121                    }
122                    catch( IOException ex ) {
123                            String errMsg = "ZIPファイルの解凍に失敗しましたã€?ファイルå�?" + fileName + "]";
124                            throw new RuntimeException( errMsg, ex );
125                    }
126                    finally {
127                            Closer.ioClose( zis );
128                            Closer.ioClose( out );
129                    }
130    
131                    return list;
132            }
133    
134            /**
135             * 引数にæŒ?®šされたファイル又ã?フィルãƒ??に存在するファイルをZIPファイルに圧縮しますã?
136             * 圧縮レベルはãƒ?ƒ•ォルトã?DEFAULT_COMPRESSIONですã?
137             * 圧縮ファイルのエントリーæƒ??として本来は、圧縮前後ã?ファイルサイズ、変更日時ã?CRCを登録する
138             * å¿?¦�がありますが、ここでは高é?化ã?ため、設定してã�?�¾せんã€?特に圧縮後ファイルサイズの取得ã?ã€?
139             * 非常に不可がかかるã€?
140             * こã?ため、ä¸?ƒ¨のアーカイバでは正しく解凍できなã�?�¯能性がありますã?
141             * 既にZIPファイルが存在する場合でもã?上書きされますã?で注意下さã�??
142             *
143             * @og.rev 4.1.0.2 (2008/02/01) 新規追åŠ?
144             *
145             * @param targetPath 圧縮対象のファイル又ã?フォルãƒ?
146             * @param zipFileName ZIPファイルå�?
147             *
148             * @return ZIPファイルのエントリーファイル名ä¸?¦§
149             */
150            public static List<String> compress( final String targetPath, final String zipFileName ) {
151                    List<String> list = new ArrayList<String>();
152                    ZipOutputStream zos = null;
153    
154                    try {
155                            zos = new ZipOutputStream( new BufferedOutputStream ( new FileOutputStream( zipFileName ) ) );
156                            File target = new File( targetPath );
157    
158                            // ZIP圧縮処ç�?‚’行いまã�?
159                            addZipEntry( zos, list, target, "", 0 );
160    
161                            zos.close();
162                    }
163                    catch( FileNotFoundException ex ) {
164                            String errMsg = "ZIPファイルが見つかりませんã€?ファイルå�?" + zipFileName + "]";
165                            throw new RuntimeException( errMsg, ex );
166                    }
167                    catch( IOException ex ) {
168                            String errMsg = "ZIP圧縮に失敗しましたã€?ファイルå�?" + zipFileName + "]";
169                            throw new RuntimeException( errMsg, ex );
170                    }
171                    finally {
172                            Closer.ioClose( zos );
173                    }
174    
175                    return list;
176            }
177    
178            /**
179             * ZIP圧縮処ç�?‚’行いますã?
180             * 引数にæŒ?®šされたFileオブジェクトがãƒ?‚£レクトリであれば再帰çš?�«呼び出しã?
181             * 下層のファイルをエントリーしますã?ä½?�—、そのãƒ?‚£レクトリ自身が空である場合ã?ã€?
182             * ãƒ?‚£レクトリをエントリーæƒ??として設定しますã?
183             *
184             * @og.rev 4.1.0.2 (2008/02/01) 新規追åŠ?
185             * @og.rev 5.1.9.0 (2010/08/01) 更新時刻の設å®?、BufferedInputStream のスコープを小さくするã?
186             *
187             * @param zos ZIP用OutputStream
188             * @param list ZIPファイルのエントリーファイル名ä¸?¦§
189             * @param target 圧縮対象のファイルオブジェクãƒ?
190             * @param prefix 処ç�?¸­のãƒ?‚£レクトリ
191             * @param depth 階層
192             */
193            private static void addZipEntry( final ZipOutputStream zos, final List<String> list, final File target, final String prefix, final int depth ) {
194    //              BufferedInputStream in = null;
195    
196                    try {
197                            // ターゲãƒ?ƒˆがディレクトリの場合ã?、ファイルが含まれてã�?‚‹かを
198                            // チェãƒ?‚¯しã?空ならã?そã?ãƒ?‚£レクトリをエントリーに追åŠ?�™るã?(æœ?¾Œに'/'がå¿?¦?
199                            // 空じゃなければ、å?起呼び出ã�?
200                            if( target.isDirectory() ) {
201                                    File[] fileList = target.listFiles();
202                                    if( fileList.length == 0 ) {
203                                            list.add( prefix + target.getName() );
204                                            ZipEntry entry = new ZipEntry( prefix + target.getName() + '/' );
205                                            zos.putNextEntry( entry );
206                                            zos.closeEntry(); // ãƒ?‚£レクトリのエントリーは空で作æ?するå¿?¦�がある。ä½?�—、FindBugsはエラー
207                                    }
208                                    else {
209                                            for( int i = 0; i < fileList.length; i++ ) {
210                                                    // 再起呼び出しを行う際ã?圧縮対象にフォルãƒ?�ŒæŒ?®šされた場合ã?
211                                                    // æœ??の再起処ç�?™‚は、エントリーにフォルãƒ??パスを含めなã�?‚ˆã�?�«するã€?
212                                                    String nextPrefix = "";
213                                                    if( depth > 0 ) {
214                                                            nextPrefix = prefix + target.getName() + '/';
215                                                    }
216                                                    addZipEntry( zos, list, fileList[i], nextPrefix, depth + 1 );
217                                            }
218                                    }
219                            }
220                            // ターゲãƒ?ƒˆがファイルの場å�?
221                            else {
222                                    list.add( prefix + target.getName() );
223                                    ZipEntry entry = new ZipEntry( prefix + target.getName() );
224                                    entry.setTime( target.lastModified() );                 // 5.1.9.0 (2010/08/01) 更新時刻の設å®?
225                                    zos.putNextEntry( entry );
226                                    BufferedInputStream in = null;
227                                    try {
228                                            in = new BufferedInputStream( new FileInputStream( target.getAbsolutePath() ) );
229                                            byte[] buf = new byte[BUF_SIZE];
230                                            int count;
231                                            while( ( count = in.read( buf, 0, BUF_SIZE ) ) != -1 ) {
232                                                    zos.write( buf, 0, count );
233                                            }
234                                    }
235                                    finally {
236    //                                      in.close();
237                                            Closer.ioClose( in );
238                                    }
239                                    zos.closeEntry();
240                            }
241                    }
242                    catch( FileNotFoundException ex ) {
243                            String errMsg = "圧縮対象のファイルが見つかりませんã€?ファイルå�?" + target.getName() + "]";
244                            throw new RuntimeException( errMsg, ex );
245                    }
246                    catch( IOException ex ) {
247                            String errMsg = "ZIP圧縮に失敗しましたã€?ファイルå�?" + target.getName() + "]";
248                            throw new RuntimeException( errMsg, ex );
249                    }
250    //              finally {
251    //                      Closer.ioClose( in );
252    //              }
253            }
254    
255            /**
256             * ファイルの圧縮またã?解凍を行いますã?
257             *
258             * @og.rev 4.1.0.2 (2008/02/01) 新規追åŠ?
259             *
260             * 使用方æ³?: java [comp or uncomp] [targetPath] [zipFileName]
261             * 第1引数 : comp:圧縮 uncomp:解å‡?
262             * 第2引数 : 圧縮æ™?圧縮対象のファイル又ã?フォルãƒ?解凍時:解凍å?のフォルãƒ?
263             * 第3引数 : ZIPファイルå�?
264             *
265             * @param args パラメータ
266             */
267            public static void main( final String[] args ) {
268                    String usage = "Usage: java [comp or uncomp] [targetPath] [zipFileName]";
269                    if( args.length < 3 ) {
270                            System.out.println( usage );
271                            return;
272                    }
273    
274                    // 開始時é–?
275                    long start = System.currentTimeMillis();
276    
277                    List<String> list = null;
278                    if( "comp".equals( args[0] ) ) {
279                            list = compress( args[1], args[2] );
280                    }
281                    else if( "uncomp".equals( args[0] ) ) {
282                            list = unCompress( args[1], args[2] );
283                    }
284                    else {
285                            System.out.println( usage );
286                            return;
287                    }
288    
289                    if( list != null ) {
290                            // 結果を表示
291                            for( String fileName : list ) {
292                                    System.out.println( fileName );
293                            }
294                            // 処ç�?™‚間を表示
295    //                      System.out.println( "処ç�?™‚é–?: " + String.valueOf( System.currentTimeMillis() - start ) + "(ms)" );
296                            System.out.println( "処ç�?™‚é–?: " + ( System.currentTimeMillis() - start ) + "(ms)" );
297                    }
298            }
299    }