@WebServlet("/down/test")
public class DownTest extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String downDir = "/Users/ham/Documents/down/";
String fname = request.getParameter("fname");
String path = downDir + fname;
File file = new File(path);
FileInputStream in = new FileInputStream(path);
fname = new String(fname.getBytes("UTF-8"), "8859_1");
//--------------------다운로드 응답을 보내기 위한 response 설정----------------------------
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=" + fname);
OutputStream os = response.getOutputStream();
//---------------------------------------------------------------------------------
int length;
byte[] b = new byte[(int) file.length()];
while ((length = in.read(b)) > 0) {
os.write(b, 0, length); // outputSteam의 write 메소드.
}
os.flush();
os.close();
in.close();
}
}
파일 다운로드 기능을 구현하려면
서버 페이지에 있는 파일을 읽어서 클라이언트에게 보내줘야 한다.
1. 파일을 다운로드 할 때 쓰일 저장소 파일 경로를 설정해준다.
String downDir = "/Users/ham/Documents/down/";
- 꼭 이 경로에 할 필요없다. 나는 편의상 Documents 파일에 넣어둠. 어디든 상관 없음.
2. 사용자가 클릭한 파일명을 읽어와 다운로드할 파일 전체 경로를 설정한다.
String fname = request.getParameter("fname");
String path = downDir + fname;
3. 파일 객체를 생성한 뒤 전체경로로 입력스트림을 생성한다.
File file = new File(path);
FileInputStream in = new FileInputStream(path);
fname = new String(fname.getBytes("UTF-8"), "8859_1");
- File 객체는 파일에 대한 정보를 가지고 있는 객체이다. (파일크기, 읽기, 쓰기, 실행가능, 존재 유무 등)
- 다운로드 파일의 내용을 프로그램을 기준으로 외부로부터 데이터를 바이너리(바이트) 형태로 읽을 입력스트림을 생성한다.
- FileInputStream 은 바이트스트림으로, 파일에서 1바이트씩 읽는 스트림이다. (한글 깨짐)
- 한글 파일명이 깨지지 않게 인코딩 처리를 해준다.
- .getBytes -- 바이너리 값으로 변환한 값을 리턴해준다.
4. 다운로드 응답을 보내기 위해 response를 설정한다.
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=" + fname);
OutputStream os = response.getOutputStream();
- .setContentType() -- 파일의 마임타입(파일종류)를 설정한다.
- octet-stream -- 바이너리 파일의 한 종류
- 패킷은 서로 통신할 수 있는 여러 정보를 헤더에 담는다. (목적지 주소, 발송지 주소 등)
- .setHeader(키, 값) -- 헤더(패킷의 중요 정보)를 설정한다. -- 이번 경우에는 첨부파일 전송을 설정함.
- Content-Disposition(=키) 은 항상 고정으로 들어감.
- attachment; filename -- 첨부파일의 파일명 정보를 값으로 추가함
- 다운로드 파일 내용을 프로그램을 기준으로 외부로 데이터를 내보내기 위해 response에 출력할 출력 스트림을 생성한다.
5. 파일 내용을 response에 출력한다.
int length;
byte[] b = new byte[(int) file.length()];
while ((length = in.read(b)) > 0) {
os.write(b, 0, length);
}
byte[] b = new byte[(int) file.length()]; 를 풀어서 쓰면
int fsize = (int) file.length();
byte[] b = new byte[fsize]; 로 쓸 수 있다.
- 다운로드 파일에서 읽은 내용을 담을 byte 배열을 파일 길이와 동일하게 생성한다.
- .length -- 파일의 길이를 long타입으로 반환한다.
long 타입은 int보다 긴 내용을 담고 있기 때문에 변환과정에서 짤릴 수 있는 위험이 있다.
- 파일의 길이만큼 읽어서 b에 담고, 배열 b의 길이가 0보다 크면(= 담긴 값이 있으면) while 문 실행~
- .read(byte[]) -- InputStream(변수명 in)의 메서드.
---- 현재 파일에서 1바이트씩 읽어들인 바이트 수를 반환한다.
- .write(byte[], off, size) -- OutputStream(변수명 os)의 메서드.
---- 배열에서 offs위치부터 size 크기만큼 출력한 바이트 수 반환.
os.write(b, 0, length);
b[0] ~ b[length] 방에 있는 값 출력
6. 출력 & 스트림 닫기
os.flush();
- 출력 스트림으로 강제 출력
os.close();
in.close();
- 출력 스트림 닫고 입력 스트림 닫기 ~
예시
DownList.java
@WebServlet("/down/list")
public class DownList extends HttpServlet {
private static final long serialVersionUID = 1L;
public DownList() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 디렉토리에 있는 파일 목록 읽어오는 코드
String downDir = "/Users/ham/Documents/down/";
File dir = new File(downDir); // 디렉토리 정보 객체 생성
String[] flist = dir.list(); // .list() : 파일 목록을 String 형태로 가져옴. {"1.jpg","2.jpg"};
request.setAttribute("flist", flist);
RequestDispatcher dis = request.getRequestDispatcher("/down/list.jsp");
dis.forward(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>파일 다운로드</h3>
<ul>
<c:forEach var="f" items="${flist }">
<li><a
href="${pageContext.request.contextPath}/down/test?fname=${f }">${f }</</a></li>
</c:forEach>
</ul>
</body>
</html>