일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 멀티프로세싱
- 티스토리챌린지
- over()
- 쿠키
- 혼공얄코
- spring security 설정
- 오버라이딩
- hackerrank
- 오버로딩
- 자바의정석
- 개인정보 수집 유효기간 자바
- 리눅스
- 객체지향
- spring security
- authenticationprovider 설정
- 자바의 정석
- 캡슐화
- spring security 커스텀
- userdetailsservice 설정
- SQL Mapper
- 멀티태스킹
- 입출력
- java
- 다형성
- 프로그래머스
- CPU
- 오블완
- 바탕화면 정리 자바
- 로그인 핸들러 구현
- 달리기 경주 자바
- Today
- Total
쉽게 쉽게
[Java] FILE 업로드(다중) 본문
1. File클래스란
java.io 패키지에서 제공하는 File 클래스는 입출력에 필요한 파일 및 디렉터리에 관한 정보를 다를 수 있다.
File 클래스는 파일과 디렉터리의 접근 권한, 생성된 시간, 마지막 수정 일자, 크기, 경로 새로운 파일과 디렉터리 생성 및 삭제, 이름 변경 등의 조작 메드를 가지고 있다.
2. File 생성자
File(String path) | 주어진 문자열 경로를 갖는 File객체 생성 ex) File dir = new File( "C:\\testDir\\test.txt" ); |
File(String dir, String name) | dir와 name문자열을 연결한 문자열로 경로를 생성하여 File객체를 생성 첫번째 매개변수에 디렉터리 경로를 넣고, 그 하위 파일명을 지정하여 생성 ex) File file = new File("C:\\testDir", "test.txt" ); |
File(File dir, String name) | dir의 파일 객체와 name문자열로 경로를 생성하여 File객체를 생성 만약 디렉터리 관련된 File객체가 이미 생성된 경우 첫번째 매개변수로 전달하고 그 하위에 있는 파일명을 문자열로 하여 File객체를 생성 ex) File dir = new File("C:\\testDir"); File file = new File(dir, "test.txt"); |
File(URI uri) | URI를 추상 경로명으로 변환하여 File 객체를 생성합니다. |
3. File 메서드 정리
File 조회 메서드
메서드 | 설명 |
File getAbsoluteFile() | 파일의 절대 경로를 반환 |
String getAbsolutePath( ) | 파일의 절대 경로를 반환 |
File getCanonicalFile() | 파일의 정규 경로를 반환 |
String getCanonicalPath( ) | 파일의 정규 경로를 반환 |
String getName( ) | 파일명을 반환 (경로는 제외) |
String getPath() | 파일의 경로를 반환 |
String getParent() | 부모 경로에 대한 경로명을 문자열로 반환 |
File getParentFile() | 부모 폴더를 File의 형태로 반환 |
long getTotalSpace() | 하드디스크의 총 용량을 반환 |
long getUsableSpace() | 하드디스크의 사용 가능한 용량을 리턴 |
long getFreeSpace() | 하드디스크의 남은 공간을 반환 |
int hashCode() | hash code를 반환 |
long lastModified( ) | 해당 경로 파일의 최종 수정 일자를 반환 1970년 1월 1일부터 현재까지의 시간을 밀리세컨드 초로 반환 |
long length( ) | 파일의 크기(파일의 길이)를 바이트로 반환 |
String[] list( ) | 특정 디렉토리의 모든 파일과 자식 디렉토리를 문자열 배열로 반환 |
String[] list(FilenameFilter filter) | filter에 만족되는 파일들과 폴더 이름을 문자열 배열로 반환 |
File[] listRoots() | 하드디스크의 루트 경로를 반환 |
File[] listFiles() | 해당 경로의 파일들과 폴더의 파일을 배열로 반환 |
File[] listFiles(FileFilter filter) | filter에 만족되는 파일들과 폴더를 File 배열로 반환 |
File[] listFiles(FilenameFilter filter) | filter에 만족되는 파일들과 폴더를 File 배열로 반환 |
File 생성/수정/삭제 메서드
메서드 | 설명 |
boolean createNewFile() | 주어진 이름의 파일이 없으면 새로 생성 |
static File createTempFile(String prefix, String suffix) | default temporary-file 디렉토리에 파일 이름에 prefix와 suffix를 붙여 임시파일을 생성 |
static File createTempFile(String prefix, String suffix, File directory) | 새로운 임시파일을 파일 이름에 prefix와 suffix를 붙여 directory 폴더에 생성 |
boolean delete() | 파일이나 폴더를 삭제 단, 폴더가 비어있지 않으면 삭제할 수 없습니다. |
void deleteOnExit() | 자바가상머신이 끝날 때 파일을 삭제 |
boolean mkdir() | 해당 경로에 폴더를 만들기 |
boolean mkdirs() | 존재하지 않는 부모 폴더까지 포함하여 해당 경로에 폴더를 만들기 |
boolean renameTo(File dest) | dest 로 File 이름을 변경 |
File 체크 메서드
메드 | 설명 |
boolean exists() | 파일의 존재 여부를 리턴 |
boolean isAbsolute() | 해당 경로가 절대경로인지 여부를 리턴 |
boolean isDirectory() | 해당 경로가 폴더인지 여부를 리턴 |
boolean isFile() | 해당 경로가 일반 file 인지 여부를 리턴 |
boolean isHidden() | 해당 경로가 숨김 file 인지 여부를 리턴 |
File 권한 메서드
메드 | 설명 |
boolean canExecute() | 파일을 실행할 수 있는지 여부를 리턴 |
boolean canRead() | 파일을 읽을 수 있는지 여부를 리턴 |
boolean canWrite() | 파일을 쓸 수 있는지 여부를 리턴 |
boolean setExecutable(boolean executable) | 파일 소유자의 실행 권한을 설정 |
boolean setExecutable(boolean executable, boolean ownerOnly) | 파일의 실행 권한을 소유자 또는 모두에 대해 설정 |
boolean setReadable(boolean readable) | 파일의 소유자의 읽기 권한을 설정 |
boolean setReadable(boolean readable, boolean ownerOnly) | 파일의 읽기 권한을 소유자 또는 모두에 대해 설정 |
boolean setReadOnly() | 파일을 읽기 전용으로 변경 |
boolean setWritable(boolean writable) | 파일의 소유자의 쓰기 권한을 설정 |
boolean setWritable(boolean writable boolean ownerOnly) | 파일의 쓰기 권한을 소유자 또는 모두에 대해 설정 |
4. File 업로드(다중)
HTML 파일 업로드
file저장한 상황이다.
<form method="post" action="/saveFile" enctype="multipart/form-data">
<input type="file" id="file1" name="file" />
<Button type="submit">전송</Button>
</form>
컨트롤러에서 호출
file을 저장하는 컨트롤러를 호출한 상황이다.
@RequestMapping(value="/saveFile" , method=RequestMethod.POST)
public String saveFile (Model model, MultipartHttpServletRequest request)throws Exception {
Map<String, Object> parameter = new HashMap<String, Object>(); // 파라미터
List<MultipartFile> file_list = request.getFiles("file"); //업로드 파일정보
//컨트롤러에서 파일업로드 호출
List content_list = new ArrayList();
for ( int i = 0 ; i < file_list.size() ; i++ ) {
HashMap row = new HashMap();
MultipartFile file = file_list.get(i);
//업로드할 파일과 파일명에 쓰일 type넘기기
Map file_map = FileUtility.file_upload(file, "test");
if ( file_map.get("file_path") != null && !file_map.get("file_path").toString().equals("") ) {
row.put("file_path", file_map.get("file_path"));
row.put("file_org_name", file_map.get("file_org_name"));
row.put("file_size", file_map.get("file_size"));
}
content_list.add(row);
}
parameter.put("content_list", content_list);
//파일정보를 담고있는 content_list를 저장하든, 수정하든, 조회하든 사용자가 원하는대로 사용하면된다.
//예를들어 파일을 저장한다면 파라미터로 넘겨주면된다.
reportService.saveFile(parameter);
return "upload/fileUploadResult";
}
File을 가져오는 파라미터 타입에 대한 궁금점(MultipartFile와 MultipartHttpServletRequest란?)
File 업로드 기능을 구현할 때, 업로드한 파일정보를 받는 방법은 여러 가지가 있다.
그중에서 제공하는 있는 MultipartFile를 사용하는 방법과 MultipartHttpServletRequest를 사용하는 방법에 대해 간략히 설명하고자 한다.
MultipartHttpServletRequest란?
MultopartHttpServletRequest 인터페이스는 스프링이 제공하는 인터페이스로서, Multipart 요청이 들어올 때 내부적으로 원본 HttpServletRequest 대신 사용되는 인터페이스이다.
MultipartHttpServletRequest 인터페이스는 HttpServletRequest 인터페이스와 MultipartRequest 인터페이스를 상속받고 있다.
MultipartHttpServletRequest 인터페이스는 HttpServletRequest 인터페이스를 상속받기 때문에 웹 요청 정보를 구하기 위한 getParameter()나 getHeader()와 같은 메서드를 사용할 수 있으며, 추가로 MultipartRequest 인터페이스가 제공하는 Multipart 관련 메서드를 사용할 수 있다.
단점으로는 HttpServletRequest를 사용해서 코드를 구현해야 한다는 점이 있어 spring이 제공하는 MultipartFile를 이용하는 방법이 더 간편하게 사용되고 있다.
MultipartFile란?
MultipartHttpServletRequest를 사용해서 파일 업로드를 구현할 수 있지만 스프링이 제공해주는 MultipartFile 인터페이스를 활용함으로써 더욱 쉽게 파일을 단일, 다중으로 업로드를 할 수 있다.
@RequestParam 어노테이션을 함께 사용하여 file 데이터를 직접 다룰 수 있다는 장점이 있다.
단 다중으로 파일을 받아올경우 여러 개의 @RequestParam를 사용해야 하기 때문에, 이 경우에는 커맨드 객체(Command Object) 방식으로 구현하는 것이 좋습니다. (사용자 정의 class)
MultipartFile로 받아오는 예시
public String upload(@RequestParam("file") MultipartFile file) throws IOException {
System.out.println(file.getName()); // 파일의 파라미터 이름
System.out.println(file.getSize()); // 파일의 사이즈
System.out.println(file.getOriginalFilename()); // 파일의 실제 이름
byte[] data = file.getBytes(); // 파일실제 내용
return "success";
}
MulripartFile 주요 메서드
메소드 | 설명 |
getName() | 파일의 이름을 구한다 |
getOriginalFilename() | 업로드한 파일의 실제이름을 구한다. |
isEmpty() | 존재여부를 확인한다.(존재하지 않은 경우 true) |
getSize() | 업로드한 파일의 크기를 구한다. |
getBytes() | 업로드한 파일 데이터를 구한다.(byte[]로 리턴) |
getInputStream() | inputStream을 구한다. |
transferTo(File dest) | 업로드 한 파일 데이터를 지정한 파일에 저장한다. |
file_upload 호출
FileUtility에 정의된 file_upload를 따라 파일 업로드가 진행되는 과정이다.
public class FileUtility {
// 로그
private static final Logger logger = Logger.getLogger(FileUtility.class);
/**
* 파일업로드
* @param file
* @param type (지정경로)
* @return
*/
public static Map file_upload (MultipartFile file, String type) {
HashMap parameter = new HashMap();
//저장경로
String savePath ="";
String path_type = type;
//저장파일명
String saveFileName = "";
String originalfileName = "";
//랜덤값(UUID는 파일의 고유 번호로, 파일명 중복 방지를 위해 적용한다)
String genId = UUID.randomUUID().toString();
//오늘날짜
Date today = new Date();
SimpleDateFormat formater = new SimpleDateFormat("yyyyMMdd");
String date = formater.format(today);
// 파일 중복명 처리
// 본래 파일명
if(file != null){
if(!file.isEmpty()){
// 파일경로
String webSavePath1 = "";
long fileSize = file.getSize() ; // 파일사이즈 반환
originalfileName = file.getOriginalFilename(); // 업로드되는 파일에서 확장자를 포함한 파일의 이름을 반환
originalfileName = Normalizer.normalize(originalfileName, Normalizer.Form.NFC); // 자소분리 방지
saveFileName = originalfileName;
// 확장자만 구하는 방법
String ext = originalfileName.substring(originalfileName.lastIndexOf(".") + 1);
// 저장되는 파일 이름
try{
//저장경로
String fullpath = "test/file_upload/"+path_type + "/" + date;
String realFilePath = "/" + fullpath;
File dir = new File(realFilePath);
if( !dir.exists() ){
dir.mkdirs();
}
savePath = realFilePath + "/" + genId; // 저장 될 파일 경로
file.transferTo(new File(savePath)); // 파일 저장
webSavePath1= "/" + fullpath + "/"+ genId;
}
catch(Exception e){
logger.error("FileUtility file_upload error : {}", e);
}
parameter.put("file_path", webSavePath1);
parameter.put("file_org_name", originalfileName);
parameter.put("file_size", fileSize);
}
}
return parameter;
}
}
자소분리 방지를 하는 이유(Normalizer)
getOriginalFilename() 메서드는 OS마다 파일 이름을 다르게 처리한다.
특히 맥(Mac)에서 getOriginalFilename() 메서드를 사용하면, 한글의 자음과 모음을 분리한다.
테스트. png를 처리하는 차이를 예시로 보면 아래와 같다.
// 맥(Mac)에서 getOrginalFilename() 한글 처리 방식
["ㅌ", "ㅔ", "ㅅ", "ㅡ", "ㅌ", "ㅡ", ".", "p", "n", "g"]
// 윈도우(Window)에서 getOrginalFilename() 한글 처리 방식
["테", "스", "트", ".", "p", "n", "g"]
DB에 Insert 된 파일명의 문자열은 "테스트"로 보이지만, 한글의 자음과 모음이 분리된 상태로 Insert 되었기에 Like 연산자가 동작하지 않는다.
이런 문제를 해결하기 위해
정규화 기능을 제공하는 Normalizer 클래스의 normalize() 메서드를 호출하여 NFC 형태로 정규화한다.
* NFC란 GNU/Linux, Windows에서 사용하는 정규화 방식, MAC은 NFD방식을 사용
originalfileName = Normalizer.normalize(originalfileName, Normalizer.Form.NFC); // 자소분리 방지
출처
https://devbox.tistory.com/entry/Java-File-%ED%81%B4%EB%9E%98%EC%8A%A4
https://www.devkuma.com/docs/java/file-class/
https://codedragon.tistory.com/6324
https://devbox.tistory.com/entry/Spring-파일업로드-처리
https://caileb.tistory.com/152
잘못된 내용이 있다면 지적부탁드립니다. 방문해주셔서 감사합니다. |
'개발공부 > Java' 카테고리의 다른 글
[Java] 최대공약수, 최소공배수 구하기 (0) | 2024.09.20 |
---|---|
[Java] 약수의 개수 구하기 (0) | 2024.09.15 |
Map에 있는 값 형변환하기 (1) | 2023.11.19 |
입출력I/O (0) | 2023.03.31 |
스트림 (0) | 2023.03.31 |