読者です 読者をやめる 読者になる 読者になる

JavaからZipファイルの作成&解凍[Java]

JavaでZipファイルの作成というと、クラスの使い方が複雑だとか、日本語ファイルが化けるとかいろいろ面倒な印象でしたが、Apach Commonsのcompressを使うといいみたいです。簡単なコードを書いて、Windows環境で3階層ぐらいのディレクトリを圧縮、解凍してみたら、とりあえず復元できたようなので公開してみます。

公式サイトからリンクされているWikiを参考にしています。

圧縮はcreateZipFile()、解凍はunpackingZipFile()を呼びます。
エラー処理は適当です。

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.commons.compress.archivers.ArchiveException;
import org.apache.commons.compress.archivers.ArchiveOutputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.compress.utils.IOUtils;

public class Zipper {

	public static void createZipFile(File zipFile, File baseDir) throws ArchiveException, IOException {
		createZipFile(zipFile, baseDir, null);
	}

	public static void createZipFile(File zipFile, File baseDir, String encording) throws ArchiveException, IOException {
		Zipper zipper = new Zipper(encording);
		zipper.zip(zipFile, baseDir);
	}

	public static void unpackingZipFile(File zipFile, File baseDir) throws ArchiveException, IOException {
		unpackingZipFile(zipFile, baseDir, null);
	}

	public static void unpackingZipFile(File zipFile, File baseDir, String encording) throws ArchiveException, IOException {
		Zipper zipper = new Zipper(encording);
		zipper.unzip(zipFile, baseDir);
	}

	private String encording = null;

	public Zipper() {
	}

	public Zipper(String encording) {
		this.encording = encording;
	}

	public void zip(File zipFile, File baseDir) throws ArchiveException, IOException {
		if (zipFile == null) {
			throw new NullPointerException("zipFile is null");
		}

		if (baseDir == null) {
			throw new NullPointerException("baseDir is null");
		}

		if (!baseDir.exists()) {
			throw new NullPointerException("[" + baseDir + "] is nothing");
		}

		OutputStream out = new BufferedOutputStream(new FileOutputStream(zipFile));
		ZipArchiveOutputStream archive = new ZipArchiveOutputStream(out);
		if (encording != null) {
			archive.setEncoding("Windows-31J");
		}

		String basePath = baseDir.getAbsolutePath();
		addAll(archive, basePath, baseDir);

		archive.finish();
		archive.flush();
		archive.close();

		out.flush();
	}

	private void addAll(ArchiveOutputStream archive, String basePath, File targetFile) throws IOException {
		if (targetFile.isDirectory()) {
			File[] children = targetFile.listFiles();

			if (children.length == 0) {
				addDir(archive, basePath, targetFile);
			} else {
				for (File file : children) {
					addAll(archive, basePath, file);
				}
			}

		} else {
			addFile(archive, basePath, targetFile);
		}

	}

	private void addFile(ArchiveOutputStream archive, String basePath, File file) throws IOException {
		String path = file.getAbsolutePath();
		String name = path.substring(basePath.length());

		archive.putArchiveEntry(new ZipArchiveEntry(name));
		IOUtils.copy(new FileInputStream(file), archive);
		archive.closeArchiveEntry();
	}

	private void addDir(ArchiveOutputStream archive, String basePath, File file) throws IOException {
		String path = file.getAbsolutePath();
		String name = path.substring(basePath.length());

		archive.putArchiveEntry(new ZipArchiveEntry(name + "/"));
		archive.closeArchiveEntry();
	}

	public void unzip(File zipFile, File baseDir) throws IOException {
		if (baseDir == null) {
			throw new NullPointerException("baseDir is null");
		}

		if (baseDir.exists() && !baseDir.isDirectory()) {
			throw new NullPointerException("[" + baseDir + "] is not directory");
		}
		baseDir.mkdirs();

		String baseDirPath = baseDir.getAbsolutePath();
		System.out.println("baseDirPath=" + baseDirPath);
		final InputStream is = new FileInputStream(zipFile);

		ZipArchiveInputStream archive;
		if (encording == null) {
			archive = new ZipArchiveInputStream(is);
		} else {
			archive = new ZipArchiveInputStream(is, encording, true);
		}

		ZipArchiveEntry entry;
		while ((entry = archive.getNextZipEntry()) != null) {
			File file = new File(baseDirPath + entry.getName());
			if (entry.isDirectory()) {
				file.mkdirs();
			} else {
				if (!file.getParentFile().exists()) {
					file.getParentFile().mkdirs();
				}
				OutputStream out = new FileOutputStream(file);
				IOUtils.copy(archive, out);
				out.close();
			}
		}

		archive.close();

	}
}

ついでなんで簡単なUIも作りました。

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;

import org.apache.commons.compress.archivers.ArchiveException;

public class ZipperSwing {
	public static void main(String[] args) throws ArchiveException, IOException {
		new ZipperSwing();
	}

	private JFrame frame = new JFrame("Zipper");
	private JTextField baseDirForZip = new JTextField("");
	private JTextField zipFileNameForZip = new JTextField("");
	private JTextField encordForZip = new JTextField("Windows-31J");
	private JTextField baseDirForUnzip = new JTextField("");
	private JTextField zipFileNameForUnzip = new JTextField("");
	private JTextField encordForUnzip = new JTextField("Windows-31J");

	private ZipperSwing() {
		JTabbedPane tab = new JTabbedPane();
		tab.add("圧縮", createZipPanel());
		tab.add("解凍", createUnzipPanel());
		frame.getContentPane().setLayout(new BorderLayout());
		frame.getContentPane().add(tab);

		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		frame.setSize(600, 200);
		frame.setVisible(true);
	}

	private JPanel createZipPanel() {
		JPanel zipPanel = new JPanel();

		zipPanel.setLayout(new BorderLayout());

		{
			JPanel panel = new JPanel();
			panel.setLayout(new GridLayout(3, 2));

			panel.add(new JLabel("圧縮対象のディレクトリまたはフォルダ"));
			panel.add(zipFileNameForZip);
			panel.add(new JLabel("作成するZIPファイル名"));
			panel.add(baseDirForZip);
			panel.add(new JLabel("ZIPファイルのファイル名のエンコード"));
			panel.add(encordForZip);
			zipPanel.add(panel, BorderLayout.CENTER);
		}

		JButton execBtn = new JButton("実行");
		execBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				zip();
			}
		});

		zipPanel.add(execBtn, BorderLayout.SOUTH);

		return zipPanel;
	}

	private JPanel createUnzipPanel() {
		JPanel zipPanel = new JPanel();

		zipPanel.setLayout(new BorderLayout());

		{
			JPanel panel = new JPanel();
			panel.setLayout(new GridLayout(3, 2));

			panel.add(new JLabel("ZIPファイル"));
			panel.add(baseDirForUnzip);
			panel.add(new JLabel("解凍先のディレクトリ"));
			panel.add(zipFileNameForUnzip);
			panel.add(new JLabel("ZIPファイルのファイル名のエンコード"));
			panel.add(encordForUnzip);
			zipPanel.add(panel, BorderLayout.CENTER);
		}

		JButton execBtn = new JButton("実行");
		execBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				unzip();
			}
		});

		zipPanel.add(execBtn, BorderLayout.SOUTH);

		return zipPanel;
	}

	private void zip() {
		String baseDir = baseDirForZip.getText();
		String zipFileName = zipFileNameForZip.getText();
		String encord = encordForZip.getText();
		try {
			Zipper.createZipFile(new File(baseDir), new File(zipFileName), encord);
		} catch (Exception e) {
			e.printStackTrace();
			JOptionPane.showMessageDialog(frame, e.getMessage(), "err", JOptionPane.WARNING_MESSAGE);
			return;
		}

		JOptionPane.showMessageDialog(frame, "finish");
	}

	private void unzip() {
		String baseDir = baseDirForUnzip.getText();
		String zipFileName = zipFileNameForUnzip.getText();
		String encord = encordForUnzip.getText();
		try {
			Zipper.unpackingZipFile(new File(baseDir), new File(zipFileName), encord);
		} catch (Exception e) {
			e.printStackTrace();
			JOptionPane.showMessageDialog(frame, e.getMessage(), "err", JOptionPane.WARNING_MESSAGE);
			return;
		}

		JOptionPane.showMessageDialog(frame, "finish");
	}
}

※このページのソースコードはパグリックドメインです。