티스토리 뷰

자바를 이용해 파일 입출력 작업시 주로 io 패키지를 이용하게된다. io를 다듬은 nio(new io) 패키지가 처음 등장한게 JDK1.5 이니 상당히 오래된 셈이지만, 상당수(내가 본 바로는 전부 다) 자바 입문서들과 블로그들이 파일입출력을 io 패키지로 소개하고있어 nio에 대해 잘 모르는 개발자들이 많다. 요즘 논블럭킹(Non-Blocking)이 이슈가 되면서 io를 논블럭킹으로 처리해주는 nio도 많이 주목을 받고있는데 이 때문인지 nio 의 n 이 non blocking인줄 알고있는 분들도 많다. 하지만 위에 괄호에 써놨듯 n 은 단지 new이며, 1.7에는 nio2 패키지가 추가되어있는 상태다. 패키지작명에 좀 실패한 케이스가 아닌가 싶다. 이번 포스팅에서는 nio를 깊게 들여다보는것보다는 아주 간단하게 nio 로 텍스트파일을 읽고 쓰는법에 대해 알아보자.


public static void main(String[] args) {
File file = new File("C:\\test.txt");

if (file.isFile()) {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(file));

String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}


전형적인 텍스트 파일을 읽어 콘솔에 출력하는 코드다. 이전 try with resources 에서 봤던대로 리팩토링을 진행해보자(중첩 try with resources 는 어떻게 작동할까?).


public static void main(String[] args) {
File file = new File("C:\\test.txt");

if (file.isFile()) {
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}


스트림 자원을 닫는 부분(finally)이 사라지면서 코드양이 많이 줄어들었다. 1/3은 사라진것같다. 이를 nio 패키지를 사용하는 코드로 변경해보자.


public static void main(String[] args) {
Path path = Paths.get("C:\\test.txt");

if (Files.exists(path)) {
try (FileChannel channel = FileChannel.open(path, StandardOpenOption.READ)) {
ByteBuffer byteBuffer = ByteBuffer.allocate((int) Files.size(path));

channel.read(byteBuffer);

byteBuffer.flip();

System.out.println(Charset.defaultCharset().decode(byteBuffer).toString());
} catch (IOException e) {
e.printStackTrace();
}
}
}


코드라인수 자체는 큰 변화가 없다. 눈여겨 봐야할 부분들은


* File 클래스에서 Path 클래스로 변경

* 다양한 정적 메서드, 팩토리 메서드 제공

* Stream에서 Channel로 변경


정도이다. Path나 Channel이 기존 io 패키지에서 제공하던 클래스들의 대체제는 맞으나 File, Stream 클래스가 Deprecated 된건 아니다. 고로 사용해도 문제없지만 nio 와 친해지고 싶다면 가급적 nio 클래스들을 사용하려해보자.


이번엔 파일 내용을 수정해보자.


private static final String content = "Hello NIO";

public static void main(String[] args) {
File file = new File("C:\\test.txt");

if (file.isFile()) {
try (BufferedWriter br = new BufferedWriter(new FileWriter(file))) {
br.write(content);
} catch (IOException e) {
e.printStackTrace();
}
}
}


읽는 부분과 비슷하지만 Reader가 Writer로 변경됐다. Stream은 읽는 작업과 쓰는 작업 중 하나만 할 수 있기때문에 용도에따라 알맞은 클래스로 변경해줘야한다.


nio 코드를 확인해보자.


private static final String content = "hello NIO";

public static void main(String[] args) {
Path path = Paths.get("C:\\test.txt");

if (Files.exists(path)) {
try (FileChannel channel = FileChannel.open(path,
StandardOpenOption.WRITE,
StandardOpenOption.TRUNCATE_EXISTING)) {
ByteBuffer byteBuffer = Charset.defaultCharset().encode(content);
channel.write(byteBuffer);
} catch (IOException e) {
e.printStackTrace();
}
}
}


Stream와 Channel의 가장 큰 차이인데 Stream은 읽거나 쓰는것 하나를 선택해야하기때문에 행위에 따라 클래스가 달라지지만 Channel은 둘 모두 할수있기때문에 변경할 필요가없다. 그 외에 파일을 여는 옵션등을 변경해줬다.


정말 io, nio, nio2 패키지가 제공하는 방대함 가운데 매우 작은 부분을 소개했다. 현업에서 개발하며 io 관련부분은 깊이 사용할 일이 많지않아 nio에 대한 공부에는 소홀했던게 사실이다. 하지만 얼마전부터 nio에 대해 조금씩 알아보고있는데 생각보다 정말 방대하고 다양한 기능들을 제공한다. 예제로 나는 FileChannel을 이용해 파일을 열고 썼지만, Files 에서 정적메서드로 제공해주는 기능을 사용하면 좀 더 수월하게(이미 저것도 수월해보이긴하는데...) 코드작성이 가능하다. 나는 이제 사소한 io 작업이라도 하게되면 익숙치않아 시간이 좀 더 걸리더라도 nio 패키지를 활용하는 쪽으로 코드를 작성하고자한다. nio랑 좀 더 친해지게되면 좀 더 깊이있는 포스팅도 작성해봐야겠다.

공유하기 링크
TAG
,
댓글
댓글쓰기 폼