Monday, March 9, 2009 / Java

Javaでzipを展開して、再度zipアーカイブを作成 ... OfficeOpenXMLデータの操作のために

MSOffice2007 では、docx,xlsx,pptx のように 拡張子に x が追加されているが、この実体は、zip ファイルで中身はXML等で構成されている。 したがって、データファイルだけを展開して中身を書きかえて、再度 zip アーカイブに戻してやれば、MSOffice なしで、内容を操作することができる。

今回はそのためのJavaコード。 このサンプルでは中身の操作は一切しないで、単に既存の sample.pptx ファイルを作業ディレクトリに展開して、その後、result.pptx ファイルにzipアーカイブとして保存しているだけ。

Test.java

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

public class Test {
    private static byte[] buf = new byte[1024];
    private static final int EOF=-1;

    private void addZipEntry(ZipOutputStream zos,String name,File file) throws Exception {
        if(file==null || file.exists()==false){
            return ;
        }

        ZipEntry ent=new ZipEntry(name);
        zos.putNextEntry(ent);
        BufferedInputStream bin = new BufferedInputStream( new FileInputStream(file) );
        int c;
        while( (c=bin.read()) != EOF){
            zos.write( (byte)c );
        }
        bin.close();
        zos.closeEntry();
    }

    public void copy(File inZipFile,File outZipFile) throws Exception {
        File tmpdir = new File("tmp");
        tmpdir.mkdirs();

        ZipOutputStream zos=new ZipOutputStream(new FileOutputStream(outZipFile));

        ZipFile zf=new ZipFile(inZipFile);
        java.util.Enumeration enu=zf.entries();

        while(enu.hasMoreElements()){
            ZipEntry ze=(ZipEntry)enu.nextElement();
            String name=ze.getName();

            File f=new File(tmpdir,name);
            f.getParentFile().mkdirs();

            FileOutputStream fout=new FileOutputStream(f);
            BufferedInputStream bin=new BufferedInputStream(zf.getInputStream(ze));                    

            try {
                for (;;) {
                    int len = bin.read(buf);
                    if (len < 0) break;
                    fout.write(buf, 0, len);
                }
            }
            finally{
                bin.close();
                fout.close();
            }

            addZipEntry(zos,name,f);
        }

        zf.close();
        zos.close();

        delete(tmpdir);
    }

    private static void delete(File f){
        if(f.isFile()){
            f.delete();
        }

        if(f.isDirectory()){
            File[] files=f.listFiles();
            for(int i=0; i<files.length; i++){
                delete( files[i] );
            }
            f.delete();
        }
    }

    public static void main(String[] args) {
        Test t = new Test();

        try{
            File in = new File("sample.pptx");
            File out = new File("result.pptx");
            t.copy(in,out);
        }
        catch(Exception ex){
            ex.printStackTrace();
        }
    }
}