하나의 게시물에 있는 다수의 파일들을 하나의 zip 압축하여 다운로드 받는 기능을 구현했다.
ZipOutputStream
, ZipEntry
을 통하여 구현했다.
아래와 같이 파일들을 준비한다.
경로: D:\zip_test_folder\
파일 목록:
four.png
one.PNG
three.PNG
two.PNG
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class FileZipModule {
private final Logger logger = LoggerFactory.getLogger(FileZipModule.class);
public void zip() {
String where = "D:/zip_test_folder";
File file_ = new File(where);
File[] listFiles = file_.listFiles();
FileOutputStream fos = null;
ZipOutputStream zipOut = null;
FileInputStream fis = null;
try {
fos = new FileOutputStream("D:/zip_test_folder/wow.zip");
zipOut = new ZipOutputStream(fos);
for(File fileToZip : listFiles) {
fis = new FileInputStream(fileToZip);
ZipEntry zipEntry = new ZipEntry(fileToZip.getName());
zipOut.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while((length = fis.read(bytes)) >= 0) {
zipOut.write(bytes, 0, length);
}
fis.close();
zipOut.closeEntry();
}
zipOut.close();
fos.close();
} catch (IOException e) {
logger.error("Error While Zipping {}", e.getMessage());
} finally {
if (fis != null) {
try {fis.close();} catch (IOException e) {logger.debug("ignoring IO Exception While FileInputStream close, {}", e.getMessage());}
}
if(zipOut != null) {
try {zipOut.closeEntry();} catch (IOException e) {logger.debug("ignoring IO Exception while ZipOutputStream -> CloseEntry, {}", e.getMessage());}
}
if (zipOut != null) {
try {zipOut.close();} catch (IOException e) {logger.debug("ignoring IO Exception while ZipOutputStream -> close, {}", e.getMessage());}
}
if (fos != null) {
try {fos.close();} catch (IOException e) {logger.debug("ignoring IO Exception While FileOutputStream close, {}", e.getMessage());}
}
}
}
/**
* 테스트 코드
*/
public static void main(String[] args) {
new FileZipModule().zip();
}
}
결과
압축파일 위치로 가면 zip 파일을 확인할 수 있다.
그리고 zip 파일에 어떤 파일이 있는 지 보면 정상적으로 zip이 생성된 것을 알 수 있다.
위에서는 그냥 로컬에서 돌린 코드고, 내가 필요한 건 HttpServletResponse에
태워서 client가 해당 파일을 다운 받도록 해야 한다.
이를 위해서 아래와 같이 코드를 조금만 응용해봤다.
@RequestMapping(value = "/downloadZipFile.do")
public void downloadZipFile(@RequestParam("bbsId") String bbsId, @RequestParam("atchmnflId") String atchmnflId, HttpServletResponse response) {
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("application/zip");
response.addHeader("Content-Disposition", "attachment; filename=\"allToOne.zip\"");
FileOutputStream fos = null;
ZipOutputStream zipOut = null;
FileInputStream fis = null;
try {
zipOut = new ZipOutputStream(response.getOutputStream());
// DB에 저장되어 있는 파일 목록을 읽어온다.
List<CmmnNttAtflDtlVO> atchmnFileInfoList = bbsService.atchmnFlList(atchmnflId);
// 실제 Server에 파일들이 저장된 directory 경로를 구해온다.
String filePath = BbsInfoFinder.mapFileLoadPath(bbsId);
// File 객체를 생성하여 List에 담는다.
List<File> fileList = atchmnFileInfoList.stream().map(fileInfo -> {
return new File(filePath + "/" + fileInfo.getStreFileNm());
}).collect(Collectors.toList());
// 루프를 돌며 ZipOutputStream에 파일들을 계속 주입해준다.
for(File file : fileList) {
zipOut.putNextEntry(new ZipEntry(file.getName()));
fis = new FileInputStream(file);
StreamUtils.copy(fis, zipOut);
fis.close();
zipOut.closeEntry();
}
zipOut.close();
} catch (IOException e) {
System.out.println(e.getMessage());
try { if(fis != null)fis.close(); } catch (IOException e1) {System.out.println(e1.getMessage());/*ignore*/}
try { if(zipOut != null)zipOut.closeEntry();} catch (IOException e2) {System.out.println(e2.getMessage());/*ignore*/}
try { if(zipOut != null)zipOut.close();} catch (IOException e3) {System.out.println(e3.getMessage());/*ignore*/}
try { if(fos != null)fos.close(); } catch (IOException e4) {System.out.println(e4.getMessage());/*ignore*/}
}
}
https://github.com/srikanth-lingala/zip4j 를 써보는 건 어떨까?
maven 을 사용한다면 pom.xml
에 dependency 를 추가한다.
<dependency>
<groupId>net.lingala.zip4j</groupId>
<artifactId>zip4j</artifactId>
<version>2.11.5</version>
</dependency>
그리고 사용법은... git repository 에서 스스로 익혀보길 바란다.
상당히 사용법을 잘 적어줬기 때문에 스스로 익히는데 어려움은 없을 거라고 생각한다.
추후에 이 라이브러리와 관련된 글을 따로 작성해보겠다.
https://www.baeldung.com/java-compress-and-uncompress
https://stackoverflow.com/questions/27952949/spring-rest-create-zip-file-and-send-it-to-the-client
디렉토리 구조도 유지하면서 zip 하기:
https://stackoverflow.com/questions/1399126/java-util-zip-recreating-directory-structure
마침 찾던기술이에요 ㅠㅠ 감사합니다