기본 콘텐츠로 건너뛰기

방송대 방통대 Java프로그래밍 10강 - java.nio 패키지의 활용 - 요약 노트 시험족보 예상문제 - 올에이클래스

Java프로그래밍 10강 - java.nio 패키지의 활용

Java프로그래밍 10강 - java.nio 패키지의 활용

기존 입출력을 개선한 Java NIO의 파일 시스템 API와 버퍼·채널 구조를 학습한다. 경로와 파일을 조작하는 PathFiles, 버퍼 상태 관리, FileChannel을 이용한 파일 입출력, 디렉터리 변화를 감지하는 WatchService까지 흐름 중심으로 정리한다.

제1장 java.nio 패키지의 개요

1. NIO의 의미와 등장

NIO는 New Input Output의 약자로 기존 java.io 패키지를 개선한 새로운 입출력 체계이다. JDK 7부터는 파일 입출력 기능을 확장한 NIO.2가 제공되며, java.nio 아래에 java.nio.file, java.nio.channels, java.nio.charset 등의 하위 패키지가 구성된다.

NIO.2는 기존 File보다 다양한 경로 기능을 제공하는 Path, 파일과 디렉터리를 정적 메서드로 조작하는 Files, 입력과 출력을 모두 수행하는 FileChannel을 제공한다. 채널과 버퍼를 결합하면 멀티스레드 환경에서도 안전한 파일 입출력을 구성할 수 있다.

비동기 파일 입출력에는 AsynchronousFileChannel을 사용할 수 있으며, 호출한 작업이 끝날 때까지 실행 흐름을 막지 않는 non-blocking 방식의 구현에 활용된다.

NIO의 핵심 구조: 파일이나 디렉터리의 위치는 Path로 표현하고, 실제 파일 조작은 Files로 수행하며, 대용량 입출력은 채널과 버퍼를 결합하여 처리한다.

제2장 Path 인터페이스

1. 경로를 객체로 표현하기

Pathjava.nio.file 패키지에 있으며 파일 시스템의 파일 또는 디렉터리 경로를 표현하는 인터페이스이다. 절대 경로와 상대 경로를 모두 표현할 수 있고, 경로 생성·비교·정보 추출·요소 조작 기능을 제공한다.

Path 객체는 Paths.get()으로 생성한다. 인수에는 파일이나 디렉터리의 절대 경로 또는 상대 경로를 명시한다. Path는 경로 자체를 나타내며 파일의 실제 생성이나 읽기·쓰기·복사·이동 같은 동작은 주로 Files의 정적 메서드에 Path를 전달해 수행한다.

Path path = Paths.get("C:\\windows\\system32\\drivers\\etc\\hosts");

2. Path의 주요 메서드

메서드기능
compareTo(Path other)두 경로를 비교하고 같으면 0을 반환
getFileName()디렉터리 또는 파일 이름을 Path로 반환
getFileSystem()해당 경로가 속한 FileSystem 객체를 반환
getName(int index)경로에서 지정 인덱스의 이름 요소를 반환
getNameCount()경로에 포함된 이름 요소의 개수를 반환
getParent()부모 경로를 반환
getRoot()루트 디렉터리 경로를 반환
iterator()경로의 이름 요소를 순회할 Iterator를 반환
toFile()Path를 기존 File 객체로 변환
toString()Path를 문자열로 변환

3. 경로 요소 순회

getNameCount()로 이름 요소의 수를 구하고 getName(i)로 각 요소를 읽을 수 있다. 또는 iterator()가 반환한 반복자를 이용해 경로 구성 요소를 차례로 순회할 수 있다. 예를 들어 전체 경로에서 파일 이름, 부모 폴더, 경로 길이를 각각 추출해 출력할 수 있다.

Windows 경로를 Java 문자열 리터럴로 작성할 때 역슬래시는 이스케이프 문자이므로 \\처럼 두 번 적어야 한다.

제3장 FileSystem과 FileStore

1. FileSystem 클래스

FileSystem은 파일 시스템에 대한 인터페이스를 제공한다. FileSystems.getDefault()는 프로그램이 실행되는 기본 파일 시스템을 반환한다. getFileStores()로 하나 이상의 저장소를 순회할 수 있고, newWatchService()로 파일 시스템 변화 감지에 사용할 감시 서비스를 만든다.

2. FileStore 클래스

FileStore는 파티션이나 볼륨과 같은 저장소를 표현한다. name()은 저장소 이름, type()은 파일 시스템 유형을 반환한다. 공간 정보는 getTotalSpace(), getUnallocatedSpace(), getUsableSpace()로 확인한다.

메서드의미
getTotalSpace()전체 저장 공간
getUnallocatedSpace()할당되지 않은 공간
getUsableSpace()현재 Java 프로그램이 사용할 수 있는 공간
FileSystem fs = FileSystems.getDefault();
for (FileStore store : fs.getFileStores()) {
    long total = store.getTotalSpace();
    long free = store.getUnallocatedSpace();
    System.out.println(store.name() + " / " + store.type());
    System.out.println("사용 중: " + (total - free));
}

제4장 Files 클래스의 파일 조작

1. Path를 받는 정적 메서드

Files는 파일과 디렉터리 조작 기능을 정적 메서드로 제공한다. 대부분의 메서드는 작업 대상을 Path 객체로 전달받는다. 파일 전체를 바이트 배열로 읽는 readAllBytes(Path)와 바이트 배열을 파일에 쓰는 write(Path, byte[])가 대표적인 읽기·쓰기 메서드이다.

파일 종류 검사에는 isDirectory(Path)isRegularFile(Path)를 사용한다. 생성·삭제에는 createFile(Path), createDirectory(Path), delete(Path)가 있고, 복사와 이동에는 copy(Path, Path), move(Path, Path)가 있다. size(Path)는 파일 크기, getOwner(Path)는 소유자 정보를 반환한다.

2. 디렉터리 내용 확인

Files.newDirectoryStream(path)는 지정한 디렉터리의 항목을 순회할 수 있는 DirectoryStream<Path>를 만든다. 각 항목에 Files.isDirectory()를 적용하면 디렉터리와 일반 파일을 구분할 수 있고, 일반 파일에는 Files.size()로 크기를 함께 출력할 수 있다.

Path path = Paths.get("C:\\Java");
try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
    for (Path item : stream) {
        if (Files.isDirectory(item)) {
            System.out.println("[디렉터리] " + item.getFileName());
        } else {
            System.out.println("[파일] " + item.getFileName()
                + " (" + Files.size(item) + ")");
        }
    }
}

제5장 버퍼의 개념과 상태

1. 버퍼의 역할

데이터 생산자와 Java 프로그램 사이 또는 Java 프로그램과 데이터 소비자 사이에는 처리 속도 차이가 생길 수 있다. 버퍼는 기본형 값을 임시로 저장하는 데이터 보관소로, 이러한 속도 차이에서 발생하는 지연을 줄인다. 프로그램은 채널과 직접 한 값씩 교환하기보다 버퍼 단위로 데이터를 입력받거나 출력한다.

Bufferjava.nio 패키지의 추상 클래스이며 공통 상태와 메서드를 선언한다. 실제 사용을 위해 boolean을 제외한 기본형별 하위 클래스인 ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer를 사용한다.

2. 버퍼 생성

ByteBuffer.allocate(크기)는 지정한 용량의 새 버퍼를 만든다. 이미 존재하는 배열을 버퍼로 다루려면 ByteBuffer.wrap(array)를 사용한다.

ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);
byte[] array = new byte[100];
ByteBuffer wrapped = ByteBuffer.wrap(array);

3. capacity, position, limit, mark

버퍼의 상태는 0 <= mark <= position <= limit <= capacity 관계로 이해할 수 있다. capacity는 생성 시 정해지는 전체 데이터 수용량이다. position은 다음에 읽거나 쓸 위치를 나타내며 작업에 따라 이동한다. limit은 읽거나 쓸 수 없는 첫 위치, 즉 접근 가능한 범위의 경계이다. markreset()으로 돌아갈 position을 기억한다.

상태 관계: capacity는 전체 크기, limit는 현재 작업 범위의 끝, position은 다음 작업 위치, mark는 되돌아갈 position의 저장점이다.

제6장 Buffer 메서드와 읽기·쓰기

1. 상태 전환 메서드

메서드동작
mark()현재 position을 mark로 저장
reset()position을 저장된 mark 위치로 이동
rewind()position을 0으로 만들고 mark를 제거하여 처음부터 다시 읽을 준비
flip()limit를 현재 position으로, position을 0으로 바꾸어 쓰기 후 읽기 준비
clear()버퍼를 초기 상태로 돌려 새로운 쓰기 준비
capacity()capacity 반환
position()현재 position 반환
limit()현재 limit 반환

채널이 버퍼에 데이터를 쓴 직후에는 position이 데이터 끝을 가리킨다. 이 상태에서 프로그램이 버퍼를 읽으려면 flip()을 호출해야 한다. 그러면 현재 position이 limit가 되고 position은 0으로 이동하여 실제 데이터가 들어 있는 범위만 읽을 수 있다. 읽기를 마친 뒤 다시 채널로부터 데이터를 받을 때는 clear()로 새로운 쓰기 상태를 준비한다.

2. 상대적 접근과 절대적 접근

상대적 읽기·쓰기 메서드는 현재 position에서 작업한 뒤 position을 자동으로 증가시킨다. ByteBuffer.get(), get(byte[]), put(byte), put(byte[])가 이에 해당한다.

절대적 메서드는 인덱스를 직접 지정하여 읽거나 쓰며 position에는 영향을 주지 않는다. get(int index)put(int index, byte value)가 대표적이다. 연속 처리에는 상대적 메서드, 특정 위치만 확인하거나 수정할 때는 절대적 메서드가 알맞다.

제7장 FileChannel 파일 입출력

1. FileChannel의 역할

FileChanneljava.nio.channels 패키지에 있으며 기존 java.io의 파일 입출력 스트림을 대체하는 채널이다. 하나의 채널이 파일 읽기와 쓰기를 모두 제공할 수 있고 멀티스레드 환경에서도 안전하게 사용할 수 있다.

읽기는 read(ByteBuffer dst), 쓰기는 write(ByteBuffer src)로 수행한다. FileChannel.open(path, options)StandardOpenOption.READ, CREATE, WRITE, APPEND 등의 옵션을 지정해 채널을 연다. 기존 FileInputStream, FileOutputStream, RandomAccessFilegetChannel()로도 채널을 얻을 수 있다.

2. 파일 쓰기

파일을 쓸 때는 먼저 부모 디렉터리를 준비하고 적절한 옵션으로 채널을 연다. 문자열은 Charset으로 인코딩하여 ByteBuffer로 만든 뒤 write()에 전달한다. 사용이 끝난 채널은 닫아야 한다.

Path path = Paths.get("C:\\Java\\temp\\file.txt");
Files.createDirectories(path.getParent());

try (FileChannel channel = FileChannel.open(path,
        StandardOpenOption.CREATE,
        StandardOpenOption.WRITE)) {
    Charset charset = Charset.defaultCharset();
    ByteBuffer buffer = charset.encode("Java NIO 파일 쓰기");
    channel.write(buffer);
}

3. 파일 읽기

읽기 채널을 열고 빈 ByteBuffer를 준비한 뒤 read(buffer)를 반복한다. 채널이 버퍼에 쓴 데이터를 프로그램이 읽기 전에 flip()으로 읽기 모드로 전환한다. 문자셋으로 디코딩한 뒤 다음 블록을 받기 위해 clear()를 호출한다.

try (FileChannel channel = FileChannel.open(path,
        StandardOpenOption.READ)) {
    ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);
    Charset charset = Charset.defaultCharset();
    StringBuffer result = new StringBuffer();

    while (channel.read(buffer) >= 0) {
        buffer.flip();
        result.append(charset.decode(buffer));
        buffer.clear();
    }
    System.out.println(result);
}
채널과 버퍼의 데이터 방향을 구분해야 한다. 파일 읽기에서는 채널이 버퍼에 쓰고 프로그램이 버퍼에서 읽으므로 flip()이 필요하다.

제8장 WatchService로 디렉터리 감시

1. WatchService의 개념

WatchService는 지정한 대상의 변화나 이벤트를 감시하는 java.nio.file의 인터페이스이다. 감시할 디렉터리를 표현하는 Path 객체를 register()로 등록하면 디렉터리 안 파일 또는 하위 디렉터리의 생성, 삭제, 수정을 감지할 수 있다.

먼저 FileSystems.getDefault().newWatchService()로 감시 서비스를 만든다. 감시 대상 경로에는 StandardWatchEventKinds.ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY 중 필요한 이벤트 종류를 등록한다.

WatchService service =
    FileSystems.getDefault().newWatchService();

Path directory = Paths.get("C:\\Java\\temp");
directory.register(service,
    StandardWatchEventKinds.ENTRY_CREATE,
    StandardWatchEventKinds.ENTRY_DELETE,
    StandardWatchEventKinds.ENTRY_MODIFY);

2. WatchKey와 이벤트 처리

take()는 이벤트가 발생할 때까지 기다린 뒤 WatchKey를 반환한다. WatchKey는 감시 상태, 감시 대상 디렉터리와 이벤트 정보를 담는다. pollEvents()WatchEvent 목록을 얻고, 각 이벤트의 kind()로 종류를, context()로 변화한 파일 이름을 확인한다.

처리를 마친 뒤에는 key.reset()을 호출해야 계속 감시할 수 있다. 반환값이 false이면 키가 더 이상 유효하지 않으므로 감시 반복을 종료한다.

while (true) {
    WatchKey key = service.take();

    for (WatchEvent<?> event : key.pollEvents()) {
        WatchEvent.Kind<?> kind = event.kind();
        Path changed = (Path) event.context();
        System.out.println(kind + ": " + changed);
    }

    if (!key.reset()) {
        break;
    }
}
감시 절차: WatchService 생성 → 디렉터리와 이벤트 종류 등록 → take()로 대기 → pollEvents()로 처리 → reset()으로 다음 감시 준비의 순서이다.

핵심 개념 정리

  • NIO는 기존 Java 입출력을 개선하며 파일 시스템, 채널, 문자셋 관련 하위 패키지를 제공한다.
  • Path는 파일이나 디렉터리 경로를 표현하고 경로 요소와 부모·루트 정보를 제공한다.
  • FileSystem은 파일 시스템, FileStore는 파티션이나 볼륨과 저장 공간을 표현한다.
  • Files는 Path를 받아 파일 검사·생성·삭제·복사·이동·읽기·쓰기를 수행하는 정적 메서드를 제공한다.
  • 버퍼는 capacity, position, limit, mark로 상태를 관리하며 flip()은 쓰기 후 읽기, clear()는 새로운 쓰기를 준비한다.
  • 상대적 get/put은 position을 이동시키고 절대적 get/put은 position에 영향을 주지 않는다.
  • FileChannel은 ByteBuffer와 결합해 파일 읽기와 쓰기를 수행한다.
  • WatchService는 디렉터리의 생성·삭제·수정 이벤트를 감시하고 WatchKey로 이벤트를 전달한다.

java.nio 활용의 핵심은 경로, 파일 조작, 데이터 이동, 이벤트 감시를 서로 다른 객체가 담당한다는 점이다. PathFiles로 파일 시스템을 다루고, FileChannelBuffer로 데이터를 이동시키며, WatchService로 디렉터리 변화를 관찰한다. 특히 버퍼의 position과 limit가 언제 바뀌는지, flip()clear()가 어느 시점에 필요한지를 정확히 이해해야 한다.

예상문제 20선

1. NIO의 의미로 옳은 것은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ①
NIO는 New Input Output의 약자로 기존 java.io의 입출력 기능을 개선한 체계이다.

2. Path 인터페이스가 표현하는 것은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ③
Path는 절대 또는 상대 경로를 객체로 표현하고 경로 구성 요소를 조작하게 한다.

3. Path에 포함된 이름 요소의 개수를 반환하는 메서드는?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ④
getNameCount()는 루트를 제외한 경로 이름 요소의 개수를 반환한다.

4. FileStore가 표현하는 대상은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ②
FileStore는 저장 장치의 파티션이나 볼륨을 나타내며 전체·미할당·사용 가능 공간을 제공한다.

5. Files 클래스에 대한 설명으로 옳은 것은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ③
Files는 생성, 삭제, 검사, 복사, 이동, 읽기, 쓰기 등의 정적 메서드를 제공한다.

6. 지정한 Path가 디렉터리인지 검사하는 메서드는?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ①
Files.isDirectory(Path)는 지정한 경로가 디렉터리인지 불리언으로 알려준다.

7. Buffer의 capacity가 의미하는 것은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ②
capacity는 버퍼 생성 시 정해지는 전체 크기이며 position과 limit는 그 범위 안에서 움직인다.

8. 버퍼에서 다음 읽기 또는 쓰기 위치를 나타내는 것은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ④
position은 상대적 get이나 put이 수행될 현재 위치이며 작업 후 자동으로 증가한다.

9. 버퍼에 데이터를 쓴 뒤 읽기 모드로 전환하는 메서드는?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ②
flip()은 현재 position을 limit로 정하고 position을 0으로 바꾸어 저장된 데이터를 읽게 한다.

10. Buffer의 rewind()가 수행하는 동작은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ①
rewind()는 limit는 유지하면서 position을 처음으로 돌려 같은 범위를 다시 읽도록 한다.

11. 버퍼의 절대적 get(int index)에 대한 설명은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ④
인덱스를 지정하는 절대적 접근은 현재 position을 이동시키지 않는다.

12. FileChannel의 패키지는?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ③
FileChannel은 채널 관련 기능을 모은 java.nio.channels 패키지에 존재한다.

13. FileChannel에서 파일 읽기에 사용하는 메서드는?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ④
채널은 파일 데이터를 대상 ByteBuffer에 넣으며 읽은 바이트 수를 반환한다.

14. 파일이 없으면 만들고 쓰기 위해 함께 사용할 수 있는 StandardOpenOption은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ②
CREATE는 파일이 없을 때 만들고 WRITE는 쓰기용 채널을 연다.

15. FileChannel로 파일을 읽을 때 일반적인 반복 순서는?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ①
채널이 버퍼에 쓴 뒤 flip으로 읽기 상태를 만들고, 처리 후 clear로 다음 채널 읽기를 준비한다.

16. WatchService가 주로 감지하는 것은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ③
WatchService는 등록된 디렉터리의 ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY 이벤트를 감시한다.

17. WatchService의 take()가 반환하는 객체는?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ①
take()는 이벤트 발생까지 기다린 뒤 이벤트와 감시 상태를 담은 WatchKey를 반환한다.

18. WatchEvent에서 변경된 파일 이름을 얻는 데 사용하는 메서드는?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ④
이벤트의 context()를 Path로 변환하면 감시 디렉터리를 기준으로 변경된 항목 이름을 얻을 수 있다.

19. WatchKey의 이벤트 처리를 마친 뒤 계속 감시하기 위해 호출하는 메서드는?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ③
key.reset()으로 키를 다시 활성화하며 false가 반환되면 감시를 종료한다.

20. Java NIO 구성 요소의 연결로 옳은 것은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ②
NIO는 경로 표현, 파일 조작, 데이터 이동, 이벤트 감시의 책임을 여러 객체로 나누어 제공한다.

댓글