카테고리 보관물: Java

Java에서 파일 이름의 유효성 체크 및 이름 바꾸기..

기본적으로 OS에서는 특수 캐릭터가 예약되어 있어, 파일 이름으로 사용할 수 없다.

그래서, 프로그램에서 파일 관련 작업을 하기 전에, 파일 이름에 대한 유효성 체크와 파일 이름에 대한 변환이 필요한 경우가 있다. 위에 대한 내용은, http://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words나 http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx#naming_conventions에서 OS별로 예약되어 있는 캐릭터와 파일의 길이를 확인할 수 있다.

아래는 위의 MSDN 링크(윈도우 OS)에 나와 있는 대표적인 캐릭터이고, 추가적인 문자열은 위 링크에서 확인할 수 있다.

< (less than)
> (greater than)
: (colon)
” (double quote)
/ (forward slash)
\ (backslash)
| (vertical bar or pipe)
? (question mark)
* (asterisk)

아래는 자바로 위의 제약조건에 대한 확인을 제공하는 클래스이다.

import java.util.regex.Pattern;
public class FileNameUtil {
	// 파일이름 확인..
	static final String ILLEGAL_EXP = "[:\\\\/%*?:|\"<>]";

	/**
	 * 파일 이름이 유효한지 확인한다.
	 * 
	 * @author mcsong@gmail.com
	 * @param fileName 파일의 이름, Path를 제외한 순수한 파일의 이름.. 
	 * @return
	 */
	public static boolean isValidFileName(String fileName) {
	    if(fileName == null || fileName.trim().length() == 0)
	    	return false;

		return !Pattern.compile(ILLEGAL_EXP).matcher(fileName).find();
	}

	/**
	 * 파일 이름에 사용할 수 없는 캐릭터를 바꿔서 유효한 파일로 만든다.
	 * 
	 * @author mcsong@gmail.com
	 * @param fileName 파일 이름, Path를 제외한 순수한 파일의 이름..
	 * @param replaceStr 파일 이름에 사용할 수 없는 캐릭터의 교체 문자
	 * @return
	 */
	public static String makeValidFileName(String fileName, String replaceStr) {
	    if(fileName == null || fileName.trim().length() == 0 || replaceStr == null)
	    	return String.valueOf(System.currentTimeMillis());		

	    return fileName.replaceAll(ILLEGAL_EXP, replaceStr);
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {

	    String c = "!\"#$%&(){}@`*:+;-.<>,^~|'[]akdfsjhex.txt"; 

	    System.out.println("bbbb --> " + isValidFileName("abcde.jpg"));
	    System.out.println("bbbb --> " + isValidFileName(c));
	    System.out.println("bbbb --> " + makeValidFileName(c, "_") );        
	}
}

위 코드는 자바 환경인 안드로이드에서도 사용할 수 있다.

Ubuntu 11.10에 JDK 설치하기..

우분투 11.10에 JDK설치하는 방법이다..
* OpenJDK 설치..

sudo apt-get install openjdk-7-jdk

* Sun JDK 설치..

sudo add-apt-repository ppa:ferramroberto/java
sudo apt-get update
sudo apt-get install sun-java6-jdk sun-java6-plugin

* Reference
http://blog.sudobits.com/2011/09/14/how-to-install-jdk-on-ubuntu-11-10/

자바(Java)에서의 LRUCache 메모리릭과 해결방안..

LRU(Least Recently Used)는 페이지를 사용하는 운영체제에서, 새로운 페이지를 할당하기 위해서 마지막에 사용한 페이지를 교체하는 알고리즘이다. LRUCache는 LRU 알고리즘을 이용하는 캐시클래스라고 보면 되겠다. 여기에서는 많이 사용하는 LRUCache 형태를 살펴보고, 이 형태가 가지고 있는 문제(메모리 릭)를 해결해 보자.

1. LRUCache 구현 방법

1.1 LinkedHashMap을 사용해서 만들기

final int MAX_ENTRIES = 100;
Map cache = new LinkedHashMap(MAX_ENTRIES+1, .75F, true) {
    // This method is called just after a new entry has been added
    public boolean removeEldestEntry(Map.Entry eldest) {
        return size() > MAX_ENTRIES;
    }
};

1.2 LinkedHashMap을 상속해서 만들기
대체로 아래의 코드가 많이 보이다. 얼핏 보기에는 잘 동작할 것으로 보인다. 하지만 시간이 지나면서 문제(메모리 릭)가 발생하게 된다.

public class LRUCache<K,V> extends LinkedHashMap<K,V> {
    private int lruSize;

    public LRUCache(int size) {
        lruSize = size;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry eldest) {
        return size() > lruSize;
    }
}

2. 해결책
해결책을 찾아보니, https://code.google.com/p/reflection-dsl/source/browse/trunk/ReflectionDsl/src/br/com/bit/ideias/reflection/cache/LRUCache.java?spec=svn204&r=204 에서는 Value에 해당하는 객체를 SoftReference(참고로, 이넘으로 객체를 래핑하게 되면 풀 GC가 읽어날때 GC대상이 된다)로 래핑해서 GC에게 위임(?)하고 있네요..

개인적으로는 명시적으로 객체를 삭제해서 메모리릭을 방지하는게 좋다고 생각한다. 잠재적인 메모리릭을 방지해 주는 코드는 아래에서 볼 수 있다.

protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
	boolean isRemove = size() > maxsize;

	if (isRemove) {
		Object obj = this.get(eldest.getKey());  
		if(obj instanceof BufferedWriter) { // V가 BufferedWriter 인스턴스임.. 
			try {
				((BufferedWriter)obj).close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		this.remove(eldest.getKey());
	}

	return isRemove;
}

이상, 자바에서 LRU 형태의 캐시클래스를 만들 때 주의가 필요한 내용을 살펴봤다.