JAVA 윈도우 환경에서 글자 깨짐 없이 Zip 압축하기

자바에서 Zip 형태로 파일을 압축하는 경우, 압축하려는 파일명이 영어가 아닌 경우가 있습니다.

이러한 경우에 Windows 환경에서 압축파일을 해제하면 글자가 깨지는 경우가 발생합니다.

이러한 경우를 가정하여 자바에서 압축하는 방법을 보도록 하겠습니다.

Mac/Linux에서 압축한 파일을 윈도우 환경에서 압축을 풀려고 할 때에도 이와 같은 현상이 발생하기도 합니다.

정확하게는 Winodws7이나 WindowsServer2008R2에서 배치가 적용이 되지 않아서 발생한다고 합니다.

프로그램 작성

파라미터로 압축할 파일이나 폴더를 sample.zip이라는 Zip 파일로 압축하는 예제를 만들겠습니다.

Java7부터는 ZipOutputStream 생성자에 Charset을 설정해줄 수 있기 때문에 Charset.forName(“Shift-JIS”)를 설정해주면 윈도우 환경에서도 글자가 깨지지 않고 Zip 파일을 만들 수 있습니다.

예전에는 org.apache.tools.zip 패키지를 넣어줘야 했지만 Java7부터는 표준 라이브러리만으로도 가능합니다. 

ZipFile.java

package com.uskey512;

import java.io.BufferedInputStream;
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.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ZipFile implements AutoCloseable {

	private byte[] buffer;
	private List<File> targetFiles;
	private ZipOutputStream zipOutputStream;

	private static final int DEFAULT_BUFFER_SIZE = 1024;

	public ZipFile(String fileName, String path) throws IOException {
		this(fileName, path, Charset.defaultCharset(), DEFAULT_BUFFER_SIZE);
	}

	public ZipFile(String fileName, String path, int bufferSize) throws IOException {
		this(fileName, path, Charset.defaultCharset(), bufferSize);
	}

	public ZipFile(String fileName, String path, Charset charset) throws IOException {
		this(fileName, path, charset, DEFAULT_BUFFER_SIZE);
	}

	public ZipFile(String fileName, String path, Charset charset, int bufferSize) throws IOException {
		File zipFile = new File(path + File.separator + fileName);
		buffer = new byte[bufferSize];
		targetFiles = new ArrayList<File>();
		zipOutputStream = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)), charset);
	}

	public void addFile(String filePath) {
		targetFiles.add(new File(filePath));
	}

	public void build() {
		writeFiles(targetFiles.toArray(new File[0]));
	}

	private void writeFiles(File[] files) {
		for (File file : files) {
			if (file.isDirectory()) {
				writeFiles(file.listFiles());
			} else {
				try {
					ZipEntry entry = new ZipEntry(file.getPath().replace('\\', '/'));
					zipOutputStream.putNextEntry(entry);
					try (InputStream is = new BufferedInputStream(new FileInputStream(file))) {
						int readLength = 0;
						while (0 < (readLength = is.read(buffer))) {
							zipOutputStream.write(buffer, 0, readLength);
						}
					}
				} catch (IOException ioe) {
					throw new RuntimeException("", ioe);
				}
			}
		}
	}

	@Override
	public void close() throws IOException {
		zipOutputStream.close();
	}
}

Main.java

package com.uskey512;

import java.io.IOException;
import java.nio.charset.Charset;

public class Main {

	public static void main(String[] args) {
		// 글자가 깨지는 것을 받지하기 위해 Charset.forName("Shift-JIS") 설정
		try (ZipFile zipFile = new ZipFile("sample.zip", ".", Charset.forName("Shift-JIS"))) { 
			zipFile.addFile(args[0]);
			zipFile.build();
		} catch (IOException ioe) {
		}
	}
}

댓글