✅ 1. java.nio 패키지
- NIO(New Input Output)는 기존 java.io 패키지를 개선한 새로운 입출력 패키지이다.
- JDK 7부터는 파일 I/O를 개선한 NIO2도 등장을 함( 이때 java.nio.file 패키지가 등장함 )
- java.nio.file, java.nio.channels, java.nio.charset 등이 있음
- File 클래스보다 다양한 기능을 제공하는 Path 클래스를 제공함. java.nio.file 안에 Path 클래스가 있음.
- Files 클래스를 제공하며, 파일/디렉터리의 조작, 파일의 읽기/쓰기 기능을 제공함
- 파일 입출력 모두 가능한 FileChannel 클래스가 있음 ( 버퍼링 기능, 멀티스레드에 안전함 )
- 입출력이 기존에는 구분이 되는 경향이 있었지만, FileChannel 클래스에서는 입출력 동시에 수행이 가능한 클래스
- 비동기식 파일 입출력을 위한 AsynchronousFileChannel 클래스를 제공함 ( non-blocking 방식 파일 입출력 )
✅ 2. Path 인터페이스
import java.nio.file.*;
import java.io.IOException;
public class SimpleNioExample {
public static void main(String[] args) throws IOException {
Path path = Paths.get("hello.txt"); // 파일 경로 생성
Files.writeString(path, "안녕하세요!"); // 파일에 문자열 쓰기
String text = Files.readString(path); // 파일에서 문자열 읽기
System.out.println("읽은 내용: " + text); // 출력: 안녕하세요!
Files.deleteIfExists(path); // 파일 삭제
}
}
- java.nio.file 패키지에 존재하며 java.io.File 클래스를 대체하는 인터페이스로 볼 수 있음.
- 파일시스템에 존재하는 파일이나 디렉터리에 해당하는 경로를 표현함 ( 절대 경로, 상대 경로로 표현됨 )
- 경로의 생성, 경로의 비교, 경로 정보 추출, 경로 요소 조작 기능 등을 제공함.
- java.nio.file.Files 클래스가 실제 파일의 대한 생성, 읽기, 쓰기, 복사, 이동 등의 작업이 가능한 클래스임.
- 즉, InputStream, OutputStream 등을 내부적으로 활용한다고 볼 수 있음.
- 해당 Files 클래스에 Path 객체의 정보를 토대로 가능한 작업임. 즉, Path 객체가 인자로 제공이 되어야 함.
- 그리고, 내부적으로 InputStream 등을 활용하고 있어, nio는 기존의 io패키지를 확장한 개념이라고 볼 수 있음.

✅ 3. FileSystem 클래스 & FileStore 클래스
(1) FileSystem
import java.nio.file.FileStore;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.io.IOException;
public class DiskInfoExample {
public static void main(String[] args) throws Exception {
FileSystem fs = FileSystems.getDefault();
for (FileStore store : fs.getFileStores()) {
System.out.println("드라이브 이름 : " + store.name());
System.out.println("파일시스템 : " + store.type());
System.out.println("전체 공간: " + store.getTotalSpace() + " bytes");
System.out.println("사용 중인 공간: " + (stroe.getTotalSpace() - store.getUsableSpace()) + " bytes");
}
}
}
- FileSystem은 파일 시스템에 대한 인터페이스를 제공함
- FileSystems.getDefault()은 기본 파일 시스템을 리턴을 해준다.
- lterable <FileStore> getFileStores() 호출 하면, FileStore 구현체를 리턴함. 운영체제에 맞는 구현체임.
- FileSystem 클래스에서 WatchService new WatchService() 객체를 리턴 받을 수 있음.
- 현재 운영체제에서 사용하는 파일 시스템에 대한 정보를 제공하고, 파일과 디렉토리 접근 방법을 제어함.
- 즉, 운영체제마다 다른 구현 클래스를 가지고 있고, Window용 JRE에는 WindowsFileSystem과 같은 구현이있음.
- 주요 역할: 경로(Path) 객체 생성, 파일 시스템의 루트 디렉토리 목록 조회 등이 있음.
(2) FileStore
- 파일 시스템 내에서 실제 스토리지 장치(디스크 파티션, 네트워크 드라이브 등) 하나를 추상화한 클래스임.
- 저장 장치의 이름, 총 공간, 사용 가능 공간, 파일 시스템 타입 등의 정보를 제공함.
- 즉, 운영체제에 따라 이것도 다르다는 것임. FileStroe도 운영체제 마다 구현 클래스를 다르게 제공함.

✅ 4. Files 클래스
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.io.IOException;
public class FilesPathExample {
public static void main(String[] args) throws IOException {
Path path = Paths.get("example.txt");
if (Files.exists(path)) {
String firstLine = Files.readAllLines(path).get(0);
System.out.println("First line: " + firstLine);
} else {
System.out.println("File does not exist.");
}
}
}
- 파일 조작 기능을 제공하는 static 메소드를 제공한다.
- 메소드는 Path 객체로 인자로 가지고 작업을 함.
- 쉽게말해, 파일 입출력 I/O 기능을 제공하는 클래스를 의미하며, Path 객체의 인자를 가지고 있어야 가능함.
(1) 주요 메서드

✅ 5. java.nio.file 정리하면..
- 정리하면, Path를 이용하려면 운영체제의 파일 정보를 알 수 있는 FileSystem 클래스의 구현체를 통해 내부적으로 알 수 있으며, Path 정보 즉, 해당 폴더의 경로를 통해 파일의 정보를 알 수 있으며, 그리고 Path 객체를 Files에 줌으로써, Files의 파일의 대한 입출력 즉, I/O가 가능해진다는 의미이다.
✅ 6. 버퍼
- 버퍼는 데이터를 임시로 저장하는 메모리 공간을 의미하며, 주로 I/O 작업에서 데이터 처리 속도를 맞추기 위해 사용됨.
- 쉽게말해, CPU는 입출력 말고도 많은 작업을 처리를 함. 이때, I/O 과정에서 입력이 들어오면 입력이 느리다고 가정하면 CPU는 입력을 다 기다려야 하는 문제가 발생함. 이때, 버퍼를 이용하면 입력과정에서 버퍼에 임시 저장을 해두고, CPU는 그 사이에 다른 일을 처리하는 느낌임. 그리고 입력이 끝나면 버퍼에서 입력을 받아 출력을 바로 해주는 방식
< 버퍼 사용 o >
[사람 입력] →→→ [버퍼] →→→ [자바 프로그램]
(느림) (임시 저장) (빠름)
< 버퍼 사용 x >
[사람 입력] →→→ [자바 프로그램]
→ 느려서 자바가 계속 기다려야 함
- 버퍼를 사용하면 지연 현상을 방지할 수 있음
- 프로그램은 버퍼로부터 데이터를 읽음(입력)
- 프로그램은 버퍼로 데이터를 출력함(출력)
✅ 7. Buffer 클래스
import java.nio.ByteBuffer;
public class ByteBufferExample {
public static void main(String[] args) {
// 1. 버퍼 생성 (용량 10바이트)
ByteBuffer buffer = ByteBuffer.allocate(10);
// 2. 데이터 쓰기 (put)
buffer.put((byte) 10);
buffer.put((byte) 20);
buffer.put((byte) 30);
// 3. 읽기 전에 버퍼를 '읽기 모드'로 전환 (flip)
buffer.flip();
// 4. 데이터 읽기 (get)
while (buffer.hasRemaining()) {
byte b = buffer.get();
System.out.println("읽은 값: " + b);
}
}
}
- 버퍼는 기본형 값을 저장하는 데이터 보관소를 의미하며, 채널 입출력에 사용되며 버퍼 단위로 입출력할 수 있음.
- 기본 Stream IO는 1바이트 또는 1문자씩 입출력을 하는데, Channel IO는 버퍼 단위로 입출력을 함.
- Buffer는 추상 클래스로 java.nio 패키지에 존재함 ( 자식 클래스에서 구현해야 할 공통의 메소드를 선언함 )
- 실제 사용을 위해 boolean을 제외한 모든 기본형에 대해 Buffer의 서브 클래스가 존재함
- ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer
- 가장 일반적인건 ByteBuffer클래스임.
(1) Buffer 클래스 생성 방법 종류
// 힙 메모리에 버퍼 생성 (자바 내부 메모리)
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 다이렉트 메모리에 버퍼 생성 (OS 네이티브 메모리)
ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024);
// 기존 바이트 배열을 감싸서 버퍼로 사용
byte[] data = new byte[10];
ByteBuffer buffer = ByteBuffer.wrap(data);
(2) Buffer 클래스 내부적인 4가지 주요 속성

- 클래스 내부 상태값 즉, 필드의 값을 의미하며, 버퍼 객체가 자체적으로 관리하는 상태 정보이다.
ByteBuffer buffer = ByteBuffer.allocate(10);
buffer.capacity() // 10
buffer.position() // 0
buffer.limit() // 10
- 이런식으로 필드값의 담기게 됨
(3) Buffer 클래스 주요 메서드

✅ 8. FileChannel 클래스
try (FileChannel channel = FileChannel.open(Paths.get("data.txt"), StandardOpenOption.READ)) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer);
buffer.flip();
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
}
- java.io 패키지의 파일 관련 입출력 스트림을 대체함.
- java.nio.channels 패키지에 존재함.
- 파일에 대한 읽기와 쓰기를 모두 제공함.
- 멀티 스레드 환경에서도 안전하게 사용할 수 있음.
- FileInputStream, FileOutputStream 보다 효율적으로 파일을 다룰 수 있도록 설계가 되어있음.
- FileChannel은 Java에서 대용량 파일 처리와 메모리 매핑을 위한 효율적인 API.
- ByteBuffer와 함께 사용되며, 기존 스트림보다 훨씬 저수준 I/O 제어가 가능함.
- 주로 파일 복사, 로그 처리, 대용량 바이너리 데이터 처리 등에 많이 사용됨.
(1) 객체 생성 방법
// 읽기 전용
FileChannel channel = FileChannel.open(Paths.get("example.txt"), StandardOpenOption.READ);
// 읽기 및 쓰기
FileChannel channel = FileChannel.open(Paths.get("example.txt"), StandardOpenOption.READ, StandardOpenOption.WRITE);
(2) 주요 메서드

(3) FileChannel 클래스 사용 예제
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
public class FileChannelReadExample {
public static void main(String[] args) throws Exception { // JVM에게 예외 위임
Path path = Path.of("example.txt"); // 읽을 파일 경로
try (FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ)) {
ByteBuffer buffer = ByteBuffer.allocate(1024); // 버퍼 생성
int bytesRead = fileChannel.read(buffer);
while (bytesRead != -1) {
buffer.flip(); // 더 이상의 작업이 없고 읽기 작업만 있다면 그때 쓰는 메서드
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
buffer.clear();
bytesRead = fileChannel.read(buffer);
}
}
}
}
(4) 정리
- 결론은 FileChannel은 java.nio.file.Path와 java.nio.file.Files 클래스를 활용하여, 더 정밀하고 효율적인 파일 입출력을 가능하게 만든 고급 파일 접근 도구다.
- java.io.File 기반이 아닌, NIO 기반의 Path/Files를 활용
- 입출력뿐 아니라 랜덤 접근, 메모리 매핑, 고성능 복사 등도 가능
- 스트림보다 더 정밀하고 낮은 수준의 제어 가능
- 읽기, 쓰기 둘 다 가능하므로, Input Output이 나뉘지 않음 클래스자체는..
✅ 9. WatchService 인터페이스
public class WatchTest {
public static void main(String[] args) throws Exception {
Path dir = Paths.get("watched"); // 감시할 폴더 (프로젝트 내부)
WatchService watchService = FileSystems.getDefault().newWatchService();
// watchService에 이벤트 감시 대상으로 등록
// ENTRY_CREATE: 파일 또는 디렉토리 생성 이벤트 감지
// ENTRY_DELETE: 삭제 이벤트 감지 MODIFY: 수정 이벤트감지
dir.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
System.out.println("Watching folder: " + dir);
WatchKey key = watchService.take(); // 이벤트 기다리기 (한 번만 감지)
for (WatchEvent<?> event : key.pollEvents()) {
System.out.println("Event: " + event.kind() + ", File: " + event.context());
}
key.reset();
}
}
- java.nio.file 패키지에서 제공하는 파일 시스템의 변경 사항을 감지하는 인터페이스이다.
- 즉, 디렉토리 내 파일의 생성, 삭제, 수정 같은 이벤트를 실시간으로 감지할 수 있게 도와주는 API이다.
- 이 기능을 통해 플링 없이도 파일 시스템을 감시하는 이벤트 기반 처리가 가능함.
- 디렉터리를 표현하는 Path 객체의 변화를 감지
- 디렉터리 내의 파일 또는 서브 디렉터리의 생성, 삭제, 수정에 대한 이벤트가 발생함을 감지한다는 의미임.
- 위의 코드는 이벤트가 발생할 때까지 블로킹 상태로 대기를 함. ( WatchKey key = watchService.take(); )
- 이벤트가 감지되면 WatchKey를 반환
- 즉, 이벤트 발생 전까지 프로그램이 멈춰서 기다리게 됨. ( 결론은 딱 한 번의 이벤트 감지 코드임. )
- WatchKey는 어떤 디렉토리에서 어떤 이벤트들이 발생했는지를 담고 있는 열쇠로 볼 수 있음.
- 리턴을 하면서 어떤 디렉토리, 어떤 이벤트가 발생했는지를 담아서 리턴해줌으로써 알 수 있게 됨.
- 또한, key.pollEvents() 메서드를 이용하면, 이벤트 하나하나에 대해서 상세히 리스트로 받을 수 있음
- 이벤트를 계속 진행하기 위해서는 boolean valid = key.reset(); 을 해 줄 수 있음.
정리하면
- take() 메서드는 WatchService가 이벤트가 발생할 때까지 대기하는 블로킹 메서드입니다. register()에 명시한 이벤트(생성, 삭제, 수정 등) 중 하나라도 발생하면, 해당 이벤트들이 WatchKey에 담겨 반환됩니다. 이렇게 반환된 WatchKey를 통해 발생한 모든 이벤트 정보를 조회할 수 있습니다.
- 그리고, key.reset() 메서드는 반드시 수행을 시켜줘야, 다음 이벤트를 감시할 수 있게됨.
'공부 > ☕Java' 카테고리의 다른 글
| [Java] 자바 스트림(Stream) 개념 + 예제 총정리 📚 (2) | 2025.06.03 |
|---|---|
| [Java] 컬렉션 프레임워크 정리: List, Set, Map 인터페이스와 대표 구현체 총정리 (0) | 2025.05.30 |
| [Java] java.io 패키지 입출력 스트림 쉽게 이해하기 (2) | 2025.05.28 |
| [Java] java.lang 패키지 정리: Object, String, Math 클래스 총정리 (0) | 2025.05.26 |
| [Java] 자바 함수형 인터페이스와 람다식(Lambda Expression) 쉽게 배우기 (1) | 2025.05.23 |