Created
March 15, 2018 09:07
-
-
Save reikop/ca10f842cacac9d700f7ce5871383682 to your computer and use it in GitHub Desktop.
파일유틸
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.dataworld.common.utils; | |
import java.awt.AlphaComposite; | |
import java.awt.Graphics2D; | |
import java.awt.Image; | |
import java.awt.RenderingHints; | |
import java.awt.image.BufferedImage; | |
import java.io.*; | |
import java.net.URLDecoder; | |
import java.net.URLEncoder; | |
import java.nio.file.*; | |
import java.nio.file.attribute.BasicFileAttributes; | |
import java.security.DigestInputStream; | |
import java.security.MessageDigest; | |
import java.security.NoSuchAlgorithmException; | |
import java.text.Normalizer; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.Collections; | |
import java.util.Comparator; | |
import java.util.List; | |
import java.util.regex.Matcher; | |
import java.util.regex.Pattern; | |
import javax.imageio.ImageIO; | |
import javax.servlet.http.HttpServletRequest; | |
import javax.servlet.http.HttpServletResponse; | |
import javax.sound.sampled.AudioFormat; | |
import javax.sound.sampled.AudioSystem; | |
import org.apache.commons.codec.digest.DigestUtils; | |
import org.apache.commons.compress.archivers.zip.*; | |
import org.apache.commons.io.IOUtils; | |
import org.apache.commons.lang3.ArrayUtils; | |
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.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import org.springframework.util.FileCopyUtils; | |
import org.springframework.web.multipart.MultipartFile; | |
/** | |
* @author reikop 파일유틸 | |
*/ | |
public class FileUtils { | |
private static Logger logger = LoggerFactory.getLogger(FileUtils.class); | |
/** | |
* 파일 목록을 ZIP으로 압축하여 outputstream에 쓴다. | |
* | |
* @param files | |
* 압축할 파일 목록 | |
* @param outputStream | |
* 아웃풋 스트림 | |
* @throws Exception | |
*/ | |
public static void writeZipStream(File[] files, OutputStream outputStream) throws Exception { | |
List<File> list = Arrays.asList(files); | |
writeZipStream(list, null, outputStream, false); | |
} | |
/** | |
* 파일 목록을 ZIP으로 압축하여 outputstream에 쓴다. | |
* | |
* @param files | |
* 압축할 파일 목록 | |
* @param outputStream | |
* 아웃풋 스트림 | |
* @throws Exception | |
*/ | |
public static void writeZipStream(List<File> files, OutputStream outputStream) throws Exception { | |
writeZipStream(files, null, outputStream, false); | |
} | |
/** | |
* 디렉토리를 선택하여 하위의 모든 폴더 및 파일을 압축한다. | |
* @param file 기준 디렉토리 | |
* @param outputStream 아웃풋스트림 | |
*/ | |
public static void writeZipStream(Path path, OutputStream outputStream) throws IOException { | |
BufferedOutputStream bos = new BufferedOutputStream(outputStream); | |
ZipArchiveOutputStream output = new ZipArchiveOutputStream(bos); | |
Files.walkFileTree(path, new Bundler(output, path)); | |
output.close(); | |
} | |
/** | |
* 한글 NFC처리 | |
*/ | |
public static String toNFC(String value) { | |
return Normalizer.normalize(value, Normalizer.Form.NFC); | |
} | |
/** | |
* | |
* pom.xml 에 추가 <dependency> <groupId>org.apache.commons</groupId> | |
* <artifactId>commons-compress</artifactId> <version>1.11</version> | |
* </dependency> | |
* | |
* | |
* 파일 목록을 ZIP으로 압축하여 outputstream에 쓴다. | |
* | |
* @param files | |
* 압축할 파일 목록 | |
* @param outputStream | |
* 아웃풋 스트림 | |
* @param force | |
* 파일이 없거나 오류날경우 무시하고 다음파일로 넘어가는지 여부 | |
* @throws Exception | |
*/ | |
public static void writeZipStream(List<File> files, List<String> filesNm, OutputStream outputStream, | |
boolean force) throws Exception { | |
ZipArchiveOutputStream zos = new ZipArchiveOutputStream(outputStream); | |
zos.setEncoding("UTF-8"); | |
int size = files.size(); | |
for (int i=0; i<size; i++) { | |
File file = files.get(i); | |
if (!file.exists()) { | |
if (force) { | |
logger.info("'" + file.getName() | |
+ "' is not Founded. will be ignored"); | |
continue; | |
} else { | |
throw new FileNotFoundException(); | |
} | |
} | |
ZipArchiveEntry entry = new ZipArchiveEntry(filesNm.get(i)); | |
zos.putArchiveEntry(entry); | |
FileCopyUtils.copy(new FileInputStream(file), zos); | |
zos.closeArchiveEntry(); | |
} | |
try { | |
zos.close(); | |
} catch (Exception e) { | |
logger.error(e.getMessage()); | |
} | |
} | |
/** | |
* 파일 목록을 ZIP으로 압축하여 outputstream에 쓴다. <br /> | |
* Response header를 자동으로 생성한다. | |
* | |
* @param files | |
* 압축할 파일목록 | |
* @param fileName | |
* 압축된 파일이름 | |
* @param request | |
* {@link HttpServletRequest} | |
* @param response | |
* {@link HttpServletResponse} | |
* @throws @throws | |
* Exception | |
*/ | |
public static void downloadZipFile(List<File> files, List<String> filesNm, String fileName, | |
HttpServletRequest request, HttpServletResponse response) throws Exception { | |
response.setContentType("application/octet-stream"); | |
response.setHeader("Content-Transfer-Encoding", "binary;"); | |
response.setHeader("pragma", "no-cache;"); | |
response.setHeader("Expires", "-1;"); | |
response.setHeader("Content-Disposition", getDisposition(fileName, request)); | |
writeZipStream(files, filesNm, response.getOutputStream(), false); | |
} | |
/** | |
* 파일 목록을 ZIP으로 압축하여 outputstream에 쓴다. <br /> | |
* Response header를 자동으로 생성한다. | |
* | |
* @param files | |
* 압축할 파일목록 | |
* @param fileName | |
* 압축된 파일이름 | |
* @param request | |
* {@link HttpServletRequest} | |
* @param response | |
* {@link HttpServletResponse} | |
* @throws Exception | |
*/ | |
public static void downloadZipFile(File[] files, String fileName, HttpServletRequest request, | |
HttpServletResponse response) throws Exception { | |
response.setContentType("application/octet-stream"); | |
response.setHeader("Content-Transfer-Encoding", "binary;"); | |
response.setHeader("pragma", "no-cache;"); | |
response.setHeader("Expires", "-1;"); | |
response.setHeader("Content-Disposition", getDisposition(fileName, request)); | |
writeZipStream(files, response.getOutputStream()); | |
} | |
/** | |
* <pre> | |
* 다국어 파일명 처리 | |
* 브라우저별 한글 파일명을 인코딩 시켜 Content-Disposition 에 해당하는 String을 리턴한다. | |
* 이 메소드를 거치지 않는다면 한글이 깨질것이다.......... | |
* 사용방법 : response.setHeader("Content-Disposition", getDisposition(fileName, request)); | |
* </pre> | |
* | |
* @param filename | |
* @param browser | |
* @return | |
* @throws UnsupportedEncodingException | |
*/ | |
public static String getDisposition(String filename, HttpServletRequest request) { | |
String header = request.getHeader("User-Agent"); | |
String browser = "Firefox"; | |
String dispositionPrefix = "attachment;filename="; | |
String encodedFilename = null; | |
try { | |
/* NFC로 한글처리 참조 : http://helloworld.naver.com/helloworld/76650 */ | |
filename = toNFC(filename); | |
if (header.indexOf("MSIE") > -1) { | |
browser = "MSIE"; | |
} else if (header.indexOf("Trident") > -1) { // IE11 | |
browser = "MSIE"; | |
} else if (header.indexOf("Chrome") > -1) { | |
browser = "Chrome"; | |
} else if (header.indexOf("Opera") > -1) { | |
browser = "Opera"; | |
} | |
if (browser.equals("MSIE")) { | |
encodedFilename = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+", "%20"); | |
} else { | |
encodedFilename = "\"" + new String(filename.getBytes("UTF-8"), "8859_1") + "\""; | |
} | |
} catch (UnsupportedEncodingException e) { | |
logger.error(e.getMessage()); | |
return dispositionPrefix + encodedFilename; | |
} | |
return dispositionPrefix + encodedFilename; | |
} | |
/** | |
* 스토리지에 중복된 파일이름이 있을경우 파일명 뒤에[n]을 붙인다. test.xml test[0].xml .... test[999].xml | |
* ... | |
* | |
* @param filename | |
* 파일명 | |
* @param filePath | |
* 파일경로 | |
* @return 중복되지 않은 파일 경로와 정보를 담은 File 객체를 리턴한다. | |
*/ | |
public static File getDeduplicationFile(String filename, String filePath) { | |
filePath = filePath.replaceAll("[\\/]", File.separator); | |
filePath = (filePath.lastIndexOf(File.separator) == (filePath.length() - 1)) ? filePath | |
: filePath + File.separator; | |
File f = new File(filePath + filename); | |
if (f.exists() && f.isFile()) { | |
String value = filename; | |
String name = ""; | |
String ext = ""; | |
String period = ""; | |
if (value.indexOf(".") > -1) { | |
name = value.substring(0, value.lastIndexOf(".")); | |
ext = value.substring(value.lastIndexOf(".") + 1, value.length()); | |
period = "."; | |
} else { | |
name = value; | |
ext = ""; | |
period = ""; | |
} | |
File fileDirec = new File(filePath); | |
ArrayList<String> ar = new ArrayList<String>(); | |
final String regex = name.replaceAll("[\\[\\]]", "") + ".*\\" + period + ext; | |
for (File fli : fileDirec.listFiles()) { | |
if (fli.getName().matches(regex)) { | |
ar.add(fli.getName()); | |
} | |
} | |
Collections.sort(ar, new WindowsExploererStringComparator()); | |
if (ar.size() > 0) { | |
value = ar.get(ar.size() - 1); | |
} | |
if (value.indexOf(".") > -1) { | |
name = value.substring(0, value.lastIndexOf(".")); | |
ext = value.substring(value.lastIndexOf(".") + 1, value.length()); | |
period = "."; | |
} else { | |
name = value; | |
ext = ""; | |
period = ""; | |
} | |
if (value.lastIndexOf("[") > -1) { | |
try { | |
int idx = Integer.parseInt(value.substring(value.lastIndexOf("[") + 1, value.lastIndexOf("]"))); | |
String realname = value.substring(0, value.lastIndexOf("[")); | |
name = realname + "[" + (idx + 1) + "]"; | |
} catch (Exception e) { | |
name += "[0]"; | |
} | |
} else { | |
name += "[0]"; | |
} | |
return new File(filePath + File.separator + name + period + ext); | |
} else { | |
return f; | |
} | |
} | |
/** | |
* 파일을 저장한다. 중복파일은 무시 한다. | |
* | |
* @param file | |
* @param upperCase | |
* @param filePath | |
* @return | |
*/ | |
public static File overwrite(MultipartFile file, String filename, String filePath) throws IOException { | |
filename = refineFileName(filename); | |
filePath = filePath.replace("/", File.separator).replace("\\", File.separator); | |
File dir = new File(filePath); | |
if (!dir.exists()) { | |
dir.mkdirs(); | |
} | |
if (!dir.isDirectory()) { | |
throw new IOException(String.format("경로 '%s' 를 생성할 수 없습니다. 퍼미션이등을 확인해주세요", dir.getAbsolutePath())); | |
} | |
File destination = new File(filePath + File.separator + filename); | |
if (destination.exists() && destination.isDirectory()) { | |
throw new IOException(String.format("경로 '%s'에 디렉토리가 생성되어 있습니다. 파일을 생성할 수 없습니다.", dir.getAbsolutePath())); | |
} else if (destination.exists()) { | |
return destination; | |
} else { | |
FileOutputStream fos = new FileOutputStream(destination); | |
BufferedOutputStream bos = new BufferedOutputStream(fos); | |
FileCopyUtils.copy(file.getInputStream(), bos); | |
fos.close(); | |
bos.close(); | |
} | |
return destination; | |
} | |
public static File overwrite(InputStream file, String filename, String filePath) throws IOException { | |
filename = refineFileName(filename); | |
filePath = filePath.replace("/", File.separator).replace("\\", File.separator); | |
File dir = new File(filePath); | |
if (!dir.exists()) { | |
dir.mkdirs(); | |
} | |
if (!dir.isDirectory()) { | |
throw new IOException(String.format("경로 '%s' 를 생성할 수 없습니다. 퍼미션이등을 확인해주세요", dir.getAbsolutePath())); | |
} | |
File destination = new File(filePath + File.separator + filename); | |
if (destination.exists() && destination.isDirectory()) { | |
throw new IOException(String.format("경로 '%s'에 디렉토리가 생성되어 있습니다. 파일을 생성할 수 없습니다.", dir.getAbsolutePath())); | |
} else if (destination.exists()) { | |
return destination; | |
} else { | |
FileOutputStream fos = new FileOutputStream(destination); | |
BufferedOutputStream bos = new BufferedOutputStream(fos); | |
FileCopyUtils.copy(file, bos); | |
fos.close(); | |
bos.close(); | |
} | |
return destination; | |
} | |
/** | |
* 파일을 저장한다. | |
* | |
* @param file | |
* 원본파일 | |
* @param filename | |
* 저장할 경로 | |
* @param filePath | |
* 저장할 경로 | |
* @return | |
* @throws IOException | |
*/ | |
public static File write(MultipartFile file, String filename, String filePath) throws IOException { | |
filename = refineFileName(filename); | |
filePath = filePath.replace("/", File.separator).replace("\\", File.separator); | |
File dir = new File(filePath); | |
if (!dir.exists()) { | |
dir.mkdirs(); | |
} | |
if (!dir.isDirectory()) { | |
throw new IOException(String.format("경로 '%s' 를 생성할 수 없습니다. 퍼미션이등을 확인해주세요", dir.getAbsolutePath())); | |
} | |
File destination = getDeduplicationFile(filename, filePath); | |
FileOutputStream fos = new FileOutputStream(destination); | |
BufferedOutputStream bos = new BufferedOutputStream(fos); | |
FileCopyUtils.copy(file.getInputStream(), bos); | |
fos.close(); | |
bos.close(); | |
return destination; | |
} | |
/** | |
* 파일을 저장한다. | |
* | |
* @param file | |
* 원본파일 | |
* @param destinationDirectory | |
* 저장할 경로 | |
* @return | |
* @throws IOException | |
*/ | |
public static File write(MultipartFile file, String filePath) throws IOException { | |
return write(file, toNFC(file.getOriginalFilename()), filePath); | |
} | |
/** | |
* 파일을 저장한다. | |
* | |
* @param sourceFile | |
* 원본파일 | |
* @param destinationDirectory | |
* 저장할 경로 | |
* @return | |
* @throws IOException | |
*/ | |
public static File write2(MultipartFile sourceFile, String fileName, String filePath) throws IOException { | |
return write(sourceFile, fileName, filePath); | |
} | |
/** | |
* 파일을 저장한다. | |
* | |
* @param sourceFile | |
* @param destinationDirctory | |
* @return | |
* @throws IOException | |
*/ | |
public static File[] write(MultipartFile[] sourceFile, String filePath) throws IOException { | |
File[] f = new File[sourceFile.length]; | |
for (int i = 0; i < sourceFile.length; i++) { | |
if (sourceFile[i].getSize() != 0) { | |
f[i] = write(sourceFile[i], filePath); | |
} | |
} | |
return f; | |
} | |
/** | |
* 파일사이즈를 KB, GB, TB 등으로 리턴하는 함수 | |
* | |
* @param bytes | |
* 파일크기 | |
* @return | |
*/ | |
public static String getFormatFileSize(long bytes) { | |
int u = 0; | |
for (; bytes > 1024 * 1024; bytes >>= 10) { | |
u++; | |
} | |
if (bytes > 1024) { | |
u++; | |
} | |
return String.format("%.1f %cB", bytes / 1024f, " KMGTPE".charAt(u)); | |
} | |
/** | |
* 이미지를 리사이즈 한다. | |
* | |
* @param imageFile | |
* 원본 이미 | |
* @param width | |
* 가로길이 | |
* @param height | |
* 세로길이 | |
* @param outputStream | |
* 변경된 이미지를 쓸 outputstream | |
* @throws IOException | |
*/ | |
public static void resizeImage(File imageFile, int width, int height, OutputStream outputStream) | |
throws IOException { | |
BufferedImage bi = ImageIO.read(imageFile); | |
Image scaledInstance = bi.getScaledInstance(width, height, Image.SCALE_SMOOTH); | |
int type = bi.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : bi.getType(); | |
BufferedImage resizedImage = new BufferedImage(width, height, type); | |
Graphics2D g = resizedImage.createGraphics(); | |
g.drawImage(scaledInstance, 0, 0, width, height, null); | |
g.dispose(); | |
g.setComposite(AlphaComposite.Src); | |
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); | |
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); | |
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); | |
ImageIO.write(resizedImage, "gif", outputStream); | |
outputStream.close(); | |
} | |
/** | |
* @param imageFile | |
* @param width | |
* @param height | |
* @param outputStream | |
* @throws IOException | |
*/ | |
public static void resizeImage(File imageFile, int width, OutputStream outputStream) throws IOException { | |
int[] size = getImageStrechSize(imageFile); | |
double ratio = size[0] / size[1]; | |
BufferedImage bi = ImageIO.read(imageFile); | |
int height = (int) (width / ratio); | |
Image scaledInstance = bi.getScaledInstance(width, height, Image.SCALE_SMOOTH); | |
int type = bi.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : bi.getType(); | |
BufferedImage resizedImage = new BufferedImage(width, height, type); | |
Graphics2D g = resizedImage.createGraphics(); | |
g.drawImage(scaledInstance, 0, 0, width, height, null); | |
g.dispose(); | |
g.setComposite(AlphaComposite.Src); | |
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); | |
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); | |
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); | |
ImageIO.write(resizedImage, "PNG", outputStream); | |
outputStream.close(); | |
} | |
public static void resizeImage(InputStream imageFile, int width, OutputStream outputStream, double ratio) | |
throws IOException { | |
imageFile.mark(0); | |
imageFile.reset(); | |
BufferedImage bi = ImageIO.read(imageFile); | |
int height = (int) (width / ratio); | |
Image scaledInstance = bi.getScaledInstance(width, height, Image.SCALE_SMOOTH); | |
int type = bi.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : bi.getType(); | |
BufferedImage resizedImage = new BufferedImage(width, height, type); | |
Graphics2D g = resizedImage.createGraphics(); | |
g.drawImage(scaledInstance, 0, 0, width, height, null); | |
g.dispose(); | |
g.setComposite(AlphaComposite.Src); | |
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); | |
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); | |
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); | |
ImageIO.write(resizedImage, "PNG", outputStream); | |
outputStream.close(); | |
} | |
/** | |
* 이미지 가로/세로사이즈를 구한다. | |
* | |
* @param f | |
* @return int[width,height] | |
*/ | |
public static int[] getImageStrechSize(File f) { | |
BufferedImage img; | |
try { | |
img = ImageIO.read(f); | |
int[] strech = new int[2]; | |
strech[0] = img.getWidth(); | |
strech[1] = img.getHeight(); | |
return strech; | |
} catch (IOException e) { | |
return null; | |
} | |
} | |
public static int[] getImageStrechSize(InputStream f) { | |
BufferedImage img; | |
try { | |
img = ImageIO.read(f); | |
int[] strech = new int[2]; | |
strech[0] = img.getWidth(); | |
strech[1] = img.getHeight(); | |
return strech; | |
} catch (IOException e) { | |
return null; | |
} | |
} | |
// | |
// /** | |
// * 동영상의 가로/세로사이즈를 구한다. | |
// * | |
// * @PARAM 가져올 파일 | |
// * @RETURN INT[WIDTH,HEIGHT] | |
// */ | |
// public static int[] getVideoStrechSize(File f){ | |
// Encoder encoder = new Encoder(); | |
// int strech[] = new int[2]; | |
// try { | |
// MultimediaInfo info = encoder.getInfo(f); | |
// strech[0] = info.getVideo().getSize().getWidth(); | |
// strech[1] = info.getVideo().getSize().getHeight(); | |
// } catch (Exception e) { | |
// strech[0] = 0; | |
// strech[1] = 0; | |
// return strech; | |
// } | |
// return strech; | |
// } | |
/** | |
* 오디오파일의 재생시간을 구한다. | |
* | |
* @param f | |
* @return 초 | |
*/ | |
public static int getAudioLength(File f) { | |
try { | |
AudioFormat fmt = AudioSystem.getAudioFileFormat(f).getFormat(); | |
long frames = fmt.getFrameSize(); | |
double durationInSeconds = (frames + 0.0) / fmt.getFrameRate(); | |
return (int) durationInSeconds; | |
} catch (Exception e) { | |
return 0; | |
} | |
} | |
/** | |
* 특정 폴더안의 모든 폴더(재귀)에 있는 내용의 파일들을 정규식으로 배열로 가지고 온다. | |
* | |
* @param pattern | |
* 정규식 | |
* @param filePath | |
* 파일경로 | |
* @return | |
*/ | |
public static ArrayList<File> findFolderInRegex(String pattern, String filePath) { | |
return findFolderInRegex(pattern, filePath, true); | |
} | |
/** | |
* 특정 폴더안에 있는 파일들을 정규식으로 배열로 가지고 온다. | |
* | |
* @param pattern | |
* 정규식 | |
* @param filePath | |
* 파일 경로 | |
* @return | |
*/ | |
public static ArrayList<File> findFolderInRegex(String pattern, String filePath, boolean findInnerFolder) { | |
File dir = new File(filePath); | |
ArrayList<File> pathList = new ArrayList<File>(); | |
File[] files = dir.listFiles(); | |
Pattern p = Pattern.compile(pattern); | |
if (files == null && !dir.isDirectory()) { | |
return null; | |
} | |
for (File file : files) { | |
if (file.isFile()) { | |
Matcher m = p.matcher(file.getName()); | |
if (m.find()) { | |
try { | |
pathList.add(new File(file.getCanonicalPath())); | |
} catch (IOException e) { | |
} | |
} | |
} else if (file.isDirectory() && findInnerFolder) { | |
try { | |
pathList.addAll(findFolderInRegex(pattern, file.getCanonicalPath().toString(), findInnerFolder)); | |
} catch (Exception e) { | |
} | |
} | |
} | |
return pathList; | |
} | |
public static String refineFileName(String value) { | |
try { | |
value = URLDecoder.decode(value, "UTF-8"); | |
} catch (UnsupportedEncodingException e) { | |
value = URLDecoder.decode(value); | |
} | |
// 특수문자 제거 | |
// value = value.replaceAll("[^a-zA-Z0-9ㄱ-힣\\.\\-\\_]", ""); | |
/* NFC로 한글처리 참조 : http://helloworld.naver.com/helloworld/76650 */ | |
value = Normalizer.normalize(value, Normalizer.Form.NFC); | |
return value; | |
} | |
public static String md5Checksum(InputStream fis) { | |
try { | |
String hex = DigestUtils.md5Hex(fis); | |
fis.close(); | |
return hex; | |
} catch (IOException e) { | |
return null; | |
} | |
} | |
public static String md5Checksum(File file) { | |
if (file != null && file.exists() && !file.isDirectory() && file.length() > 0) { | |
try { | |
FileInputStream fis = new FileInputStream(file); | |
return md5Checksum(fis); | |
} catch (FileNotFoundException e) { | |
return null; | |
} | |
} | |
return null; | |
} | |
/** | |
* 파일에 대해 섬네일을 생성한다. | |
* | |
* @param file | |
* @param string | |
* @return | |
* @throws IOException | |
* @throws FileNotFoundException | |
*/ | |
public static File thumbnail(File file, String path) throws FileNotFoundException, IOException { | |
File output = new File(path); | |
output.getParentFile().mkdirs(); | |
FileOutputStream fos = new FileOutputStream(output); | |
BufferedOutputStream bos = new BufferedOutputStream(fos); | |
resizeImage(file, 200, bos); | |
return output; | |
} | |
public static FileOutputStream getOutputStream(String path, String filename) { | |
try { | |
mkdir(path); | |
File file = new File(concat(path, filename)); | |
return new FileOutputStream(file); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
return null; | |
} | |
public static String concat(String filepath, String filename){ | |
return filepath.replaceAll("/$", "") + File.separator + | |
filename.replaceAll("^/", ""); | |
} | |
public static File mkdir(String path) throws IOException { | |
File dir = new File(path); | |
if (!dir.exists()) { | |
dir.mkdirs(); | |
} | |
if(!dir.isDirectory()) { | |
throw new IOException(String.format("경로 '%s' 를 생성할 수 없습니다. 퍼미션이등을 확인해주세요", dir.getAbsolutePath())); | |
} | |
return dir; | |
} | |
// /** | |
// * 바이트를 Hex값으로 변환한다. | |
// * | |
// * @param hash | |
// * @return | |
// */ | |
// private static String byteArray2Hex(byte[] hash) { | |
// Formatter formatter = new Formatter(); | |
// for (byte b : hash) { | |
// formatter.format("%02x", b); | |
// } | |
// String s = formatter.toString(); | |
// formatter.close(); | |
// return s; | |
// } | |
} | |
class Bundler extends SimpleFileVisitor<Path> { | |
private ZipArchiveOutputStream out; | |
private Path root; | |
private Path prefix; | |
public Bundler(ZipArchiveOutputStream outputStream, Path root) { | |
this.out = outputStream; | |
this.root = root; | |
} | |
private String getEntryName(Path path) { | |
return root.relativize(path).toString(); | |
} | |
private InputStream getInputStream(Path path) throws FileNotFoundException { | |
FileInputStream fin = new FileInputStream(path.toFile()); | |
return new BufferedInputStream(fin); | |
} | |
@Override | |
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { | |
String entryName = getEntryName(dir); | |
if (!entryName.equals("")) { | |
ZipArchiveEntry entry = new ZipArchiveEntry(dir.toFile(), entryName); | |
out.putArchiveEntry(entry); | |
out.closeArchiveEntry(); | |
} | |
return FileVisitResult.CONTINUE; | |
} | |
@Override | |
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { | |
String entryName = getEntryName(file); | |
ZipArchiveEntry entry = new ZipArchiveEntry(file.toFile(), entryName); | |
out.putArchiveEntry(entry); | |
IOUtils.copy(getInputStream(file), out); | |
out.closeArchiveEntry(); | |
return FileVisitResult.CONTINUE; | |
} | |
} | |
/** | |
* 윈도우방식으로 파일 정렬을 해준다. 자바 기본은 [1, 10, 2, 3] 윈도우방식은 [1, 2, 3, 10] | |
* | |
* @author reikop | |
*/ | |
class WindowsExploererStringComparator implements Comparator<String> { | |
private String str1, str2; | |
private int pos1, pos2, len1, len2; | |
public int compare(String s1, String s2) { | |
str1 = s1; | |
str2 = s2; | |
len1 = str1.length(); | |
len2 = str2.length(); | |
pos1 = pos2 = 0; | |
int result = 0; | |
while (result == 0 && pos1 < len1 && pos2 < len2) { | |
char c1 = str1.charAt(pos1); | |
char c2 = str2.charAt(pos2); | |
if (Character.isDigit(c1)) { | |
result = Character.isDigit(c2) ? compareNumbers() : -1; | |
} else if (Character.isLetter(c1)) { | |
result = Character.isLetter(c2) ? compareOther(true) : 1; | |
} else { | |
result = Character.isDigit(c2) ? 1 : Character.isLetter(c2) ? -1 : compareOther(false); | |
} | |
pos1++; | |
pos2++; | |
} | |
return result == 0 ? len1 - len2 : result; | |
} | |
private int compareNumbers() { | |
int end1 = pos1 + 1; | |
while (end1 < len1 && Character.isDigit(str1.charAt(end1))) { | |
end1++; | |
} | |
int fullLen1 = end1 - pos1; | |
while (pos1 < end1 && str1.charAt(pos1) == '0') { | |
pos1++; | |
} | |
int end2 = pos2 + 1; | |
while (end2 < len2 && Character.isDigit(str2.charAt(end2))) { | |
end2++; | |
} | |
int fullLen2 = end2 - pos2; | |
while (pos2 < end2 && str2.charAt(pos2) == '0') { | |
pos2++; | |
} | |
int delta = (end1 - pos1) - (end2 - pos2); | |
if (delta != 0) { | |
return delta; | |
} | |
while (pos1 < end1 && pos2 < end2) { | |
delta = str1.charAt(pos1++) - str2.charAt(pos2++); | |
if (delta != 0) { | |
return delta; | |
} | |
} | |
pos1--; | |
pos2--; | |
return fullLen2 - fullLen1; | |
} | |
private int compareOther(boolean isLetters) { | |
char c1 = str1.charAt(pos1); | |
char c2 = str2.charAt(pos2); | |
if (c1 == c2) { | |
return 0; | |
} | |
if (isLetters) { | |
c1 = Character.toUpperCase(c1); | |
c2 = Character.toUpperCase(c2); | |
if (c1 != c2) { | |
c1 = Character.toLowerCase(c1); | |
c2 = Character.toLowerCase(c2); | |
} | |
} | |
return c1 - c2; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment