공부/java2014. 9. 5. 09:44

FileWriter 클래스가 어떻게 문자 스트림을 사용하는지에 대해 알아 보겠습니다. 기본적으로 파일을 사용할 수 있는지 혹은 생성이나 삭제가 가능 할지는 플랫폼(MAC, Linux, Windows ETC) 에 따라 달라집니다. 일부 플랫폼들은 특별히 파일을 쓰기 위해 여는 작업을 한번에 오직 하나의 FileWriter 객체를 사용 할 수 있습니다. 이러한 상황에에서는 관련된 파일이 이미 열려 있는 경우 FileWriter 생성자 호출은 실패 하게 됩니다.

FileWriter 클래스는 OutputStreamWriter 클래스를 확장하며 문자 스트림과 바이트 스트림 사이에 다리 역활을 합니다. 여기에 기록된 문자는 지정된 캐릭터셋을 이용하여 바이트로 인코딩 됩니다. 이 캐릭터셋은 지정된 이름을 사용하거나 명시적으로 부여 할 수 있고 또는 플랫폼들의 기본 캐릭터셋을 사용하게 됩니다.

FileWriter 클래스는 JDK 1.1 부터 존재 했습니다. 

FileWriter 클래스 구조

생성자
  • FileWriter(File file)
    File 객체를 매개변수로 넘겨 FileWriter 객체를 생성합니다.


  • FileWriter(File file, boolean append)
    File 객체를 매개변수로 넘겨 FileWriter 객체를 생성합니다. 만약 두번째 매개변수값이 true 이면 파일의 마지막 다음 줄 첫번째에 바이트를 쓰게 됩니다.


  • FileWriter(FileDescriptor fd)
    File descriptor 와 관련된 FileWriter 객체를 생성합니다.


  • FileWriter(String filename)
    지정된 파일이름으로 FileWriter 객체를 생성합니다.


  • FileWriter(String filename, boolean append)
    지정된 파일이름으로 FileWriter 객체를 생성합니다. 만약 두번째 매개변수값이 true 이면 파일의 마지막 다음 줄 첫번째에 바이트를 쓰게 됩니다.

FileWriter 예제를 살패 보겠습니다

FileWriter 의 기본적인 사용 예제 입니다.

package kr.co.leehana.example.filewriter;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

public class SimpleFileWriterExample {

	private static final String LINE_SEPARATOR = System
			.getProperty("line.separator");

	// jdk 7
	// private static final String LINE_SEPARATOR = System.lineSeparator();

	public static void main(String[] args) throws IOException {
		String name = "Hana Lee";
		int age = 37;
		double temp = 27.3d;
		FileWriter fw = null;

		try {
			fw = new FileWriter(new File("textfile.txt"));

			fw.write(String.format("My name is %s.", name));
			fw.write(LINE_SEPARATOR);
			fw.write(String.format("I am %d years old.", age));
			fw.write(LINE_SEPARATOR);
			fw.write(String.format("Today's temperature is %.2f.", temp));
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (fw != null)
				fw.close();
		}
		
		System.out.println("Done");
	}
}

예제에서 매개변수로 새로운 File 객체를 만들어 전달하여 FileWriter 객체를 생성하고 파일에 문자를 쓸때 System.lineSeparator 를 사용하여 줄바꿈을 해줬습니다. 파일에 더 이상 쓸 내용이 없을때 FileWriter 객체의 close 메소드를 호출 하여 닫아 주었습니다.
textfile.txt 파일을 열어보면 소스상에 적용된 문자가 입력되어 있는것을 확인 할 수 있습니다.

FileWriter 의 append 에 대한 예제 입니다.

FileWriter 의 append 매개변수 사용방법에 대한 예제 입니다. 이 예제에서 간단한 Logger 객체를 만들어서 로그 데이터를 파일에 작성하겠습니다.

package kr.co.leehana.example.filewriter;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;

public class Logger {
	private static final String LINE_SEPARATOR = System
			.getProperty("line.separator");
	private File logFile;

	public Logger() {
	}

	public Logger(String fileName) {
		this.logFile = new File(fileName);
	}

	public Logger(File logFile) {
		this.logFile = logFile;
	}

	public void log(String str) {
		FileWriter fw = null;
		try {
			fw = new FileWriter(this.logFile, true);
			String date = new Date().toString();
			fw.write(date + " : " + str);
			fw.write(LINE_SEPARATOR);
		} catch (IOException e) {
			System.err.println("Couldn't log this : " + str);
		} finally {
			if (fw != null) {
				try {
					fw.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

아래 클래스는 Logger 객체를 생성하고 log 메소드를 호출할때 로그 데이터를 매개변수로 넘겨 파일에 로그 데이터를 쓰는 작업을 하게 됩니다.
Logger 객체를 생성할때 두가지 다른 생성자를 만들어서 테스트 해볼 수 있는 예제 입니다.

package FileWriterAppendExample;

import java.io.File;

import kr.co.leehana.example.filewriter.Logger;

public class FileWriterAppendExample {

	public static void main(String[] args) {
		Logger log1 = new Logger("file1.log");

		File logFile = new File("file2.log");
		Logger log2 = new Logger(logFile);

		log1.log("This is written in the first file");
		log2.log("This is written in the second file");

		log1.log("This is appended to the first file");
		log2.log("This is appended to the second file");
	}
}

추가 정보

FileWriter 클래스의 모든 생성자들은 매개변수로 넘어온 File 객체나 파일이름이 이미 존재 하면서 디렉토리 일때 혹은 파일 생성이 되지 않거나 어떤 이유로 파일 열기가 되지 않을 경우 IOException 오류가 발생합니다.




소스 코드

출처


'공부 > java' 카테고리의 다른 글

Java BufferedWriter 예제  (0) 2014.09.06
Java List 를 배열로 변환 하는 예제  (0) 2014.09.05
RejectedExecutionException 해결 방법 알아보기  (0) 2014.09.03
예외  (0) 2014.06.20
POJO  (0) 2014.06.10
Posted by #HanaLee
공부/java2014. 9. 3. 15:39

java.util.concurrent.RejectedExecutionException 을 해결 하는 방법에 대해 예제 코드와 해결 방법에 대하여 이야기 해보겠습니다.

threads 를 만들어서 Executor 인터페이스를 이용하여 실행 하는 경우 실행 할 수 없는 상태가 될 수도 있습니다.

이것은 몇가지 이유가 있을 수 있고 아래의 예제를 통해 보여드리도록 하겠습니다.

그리고 RejectedExecutionExceptionjava.lang.RuntimeException 이라는 것을 주목 할 필요가 있습니다.

1. 간단한 Executor 샘플

RejectedExecutionException 예외를 설명 하기 위해 ThreadPoolExecutor 를 이용하여 몇개의 worker thread 들을 실행하는 간단한 java 어플리케이션을 만들것입니다.

어떻게 만들었는지 아래의 코드를 보겠습니다.

아래의 코드는 ThreadPoolExecutor 클래스가 어떻게 당신이 만든 task 들을 몇개의 thread 들을 만들어 실행하는지 보여줍니다.

프로그램을 실행하면 정상적으로 실행 되는 것을 확인할 수 있습니다.

우리는 ThreadPoolExecutor 를 이용하였는데 pool 의 크기를 3으로 설정 하였습니다.

이것이 의미 하는것은 3개의 thread 들을 만들것이고 3개의 task worker 들을 채워 넣을것입니다.

우리가 새로운 task 를 만들어 ThreadPoolExecutor 에 submit 을 하게 되면 3개의 pool 중 하나가 사용 가능 하게 될때까지 BlockingQueue 에 배치하고 대기 하게 됩니다.

이 예제의 경우 15의 크기를 가지는 ArrayBlockingQueue 를 사용합니다. ArrayBlockingQueue 를 사용한 이유는 나중에 설명 합니다.

예제에서 우리는 10개의 task 들을 만들어 실행 할 것입니다.

2. 간단한 RejectedExecutionException 예제

RejectedExecutionException 의 한가지 이유중에는 새로운 task 를 executor 가 shutdown 된 후에 실행 하려고 할때 발생합니다.

shutdown 메소드가 호출 된 후에는 오래된 task 들은 여전히 실행되지만, 더이상 새로운 task 들을 실행 할 수 없게 됩니다.

이 오류에 대한 내용을 아래의 예제를 통해 확인 해보겠습니다.

프로그램을 실행하게 되면 RejectedExecutionException 이 출력 될 것입니다.

3. RejectedExecutionException 두번째 예제

Executor 가 그의 책임 아래 더이상 task 들을 처리 할 수 없을때 나타나는 예제 입니다.

로컬 메모리의 한계에 도달했을 때 Exception 이 발생합니다.

이 예제에서 로컬 메모리는 ArrayBlockingQueue 의 크기인 15 에 해당합니다.

만약 ArrayBlockingQueue 에 저장 할 수 있는 것보다 더 많은 task 들을 실행 하려고 하면 RejectedExecutionException 이 발생합니다.

예제를 살펴 보겠습니다.

15의 크기를 가지는 ArrayBlockingQueue 는 자신의 크기인 15 보다 더 많은 thread 들을 저장 할 수 없습니다.

하지만 예제에서 우리는 20개의 thread 들을 실행 하려고 하였습니다.

20개의 thread 가 빠르게 처리 된다면 오류가 발생 하지 않을 수도 있지만 우리는 Worker.java 코드에서 Thread.sleep() 으로 딜레이를 주었기 때문에 ThreadPoolExecutor 에서 빠르게 처리 하지 못하고 BlockingQueue 에 저장하게 되는데 이때 15개를 넘어가기 때문에 오류가 발생 한것입니다.

만약 18개의 thread 들을 만들었다면 정상적으로 실행 될 것입니다. 한번 생각해보는것도 좋을꺼 같습니다.

4. RejectedExecutionException 해결 방안

먼저 다음 두가지의 경우를  체크 해봅니다.

  1) shutdown 메소드가 호출 된 후 Executor 가 실행 되는것을 주의 해서 프로그래밍을 한다.

  2) Executor 가 처리 할 수 있는 것보다 더 많은 task 들을 실행 하지 않는다.

두번째의 경우는 쉽게 해결이 가능 합니다. 크기에 제한이 없는 자료구조를 이용 하면 됩니다.

예를 들면 LinkedBlockingQueue 가 있습니다.

만약 LinkedBlockingQueue 를 사용 하였는데도 여전히 문제가 발생한다면 첫번째 케이스를 의심 해봐야 합니다.

만약 첫번째 케이스에도 해당하지 않는다면 분명 여러가지 복합적인 문제가 있을 수 있습니다.

예를 들면 다른 thread 들이 deadlock 에 걸려 메모리가 꽉 차거나 LinkedBlockingQueue 는 제한 없이 계속 쌓이므로 메모리의 사용이 많아져서 문제가 발생 할 수 있습니다.

우리는 두번째 케이스를 좀 더 세밀하게 촛점을 맞춰 해결하려고 합니다.

ThreadPoolExecutor 는 15개 보다 더 많은 task 들을 처리 할 수 있습니다. 

이 예제에서는 ArrayBlockingQueue 를 사용하고 있고 이는 새로운 task 가 실행되기 전에 처리가 완료된다면 자연스럽게 오류가 없이 실행이 될 수 있습니다.

약간의 꼼수 같은 예제 이지만 한번 살펴 보겠습니다.

예제를 실행 해보면 문제없이 실행 되는것을 확인 할 수 있습니다.

예제를 실행해 보면 마치 ThreadPoolExecutor 가 15개 이상의 task 들을 처리 할 수 있는 것 처럼 보이지만 사실 약간의 꼼수를 이용하여 딜레이를 줘 ThreadPoolExecutor 가 이미 처리 중인 task 들이 충분히 처리 되어 queue 를 비울 수 있는 시간을 벌게 해줬기 때문에 가능한것이다. Thread.sleep(3000); 이부분은 꼭 3000 이 아니라 적절한 값을 주면 됩니다.




소스

예제 출처 : 


'공부 > java' 카테고리의 다른 글

Java List 를 배열로 변환 하는 예제  (0) 2014.09.05
Java FileWriter 예제  (0) 2014.09.05
예외  (0) 2014.06.20
POJO  (0) 2014.06.10
자바의 주요 특징 및 개인적인 생각  (0) 2014.06.08
Posted by #HanaLee

daum-map-addon-firefox v0.1.2

Daum Map Addon for Firefox (파이어폭스용 다음지도 확장기능)

사용방법

  1. 웹사이트를 이용중 주소를 발견하면 클립보드에 복사를 합니다. (Ctrl+C or Cmd+C)

  2. 다음 지도 애드온 버튼을 누르면 아래의 이미지 처럼 복사된 내용을 가지고 검색 한 내용이 출력됩니다.



  3. 지도를 초기화 하고 싶을때에는 초기화 버튼을 누르면 아래와 같이 초기화가 됩니다.



  4. 큰화면에서 더 많은 기능을 이용하고자 할때에는 큰지도 보기를 누르면 현재 검색된 텍스트를 이용하여 다음지도 화면으로 이동합니다 (http://map.daum.net)


Posted by #HanaLee