IO는 파일의 속성을 읽기 위해 File 클래스만 제공한다.
NIO는 더 다양한 파일의 속성 정보를 제공해주는 클래스와 인터페이스를 java.nio.file, java.nio.file.attribute 패키지에서 제공해준다.
📌경로 정의(Path)
java.nio.file.Paths
Path get(String first, String second, String... more) Path get(URI uri); |
입력한 path 리턴 (절대 경로, 상대 경로 모두 가능) |
Path getFileName() | 부모 경로를 제외한 파일 또는 디렉토리 이름만 가진 Path리턴 |
Path getName(int index) | C:\Temp\dir\file.txt 일경우 index:0 이면 "Temp"의 Path 객체 리턴 index:1 이면 "dir"의 Path 객체 리턴 index:2 이면 "file.txt"의 Path 객체 리턴 |
Path getParent() | 바로 위 부모 폴더의 Path 리턴 |
Path getRoot() | 루트 디렉토리의 Path 리턴 |
Pth normalize() | 상대 경로로 표기할 때 불필요한 요소를 제거 C:\Temp\dir1\..\dir2\file.txt 이면 C:\Temp\dir2\file.txt |
int compareTo(Path other) | 파일 경로가 동일하면 0을 리턴, 상위 경로면 음수, 하위 경로면 양수를 리턴, 값의 크기는 음수와 양수 값의 차이나는 문자열의 수 |
FileSystem getFileSystem() | FileSystem 객체 리턴 |
int getNameCount() | 중첩 경로 수, C:\Temp\dir\file.txt일 경우 3을 리턴 |
Iterator<Path> iterator() | 경로에 있는 모든 디렉토리와 파일을 Path 객체로 생성하고 반복자를 리턴 |
WatchKey register(...) | WatchService를 등록(와치 서비스에서 설명함) |
File toFile() | java.io.File 객체로 리턴 |
String toString() | 파일 경로를 문자열로 리턴 |
URI toUri() | 파일 경로를 URI 객체로 리턴 |
Path path = Paths.get("C:/Temp/dir/file.txt");
Path path = Paths.get("C:/Temp/dir","file.txt");
Path path = Paths.get("C:", "Temp", "dir", "file.txt");
//현재 디렉터이 위치: "C:\TEMP" 인 경우
Path path = Paths.get("dir/file.txt");
Path path = Paths.get("./dir/file.txt");
📌파일 시스템 정보(FileSystem)
운영체제의 파일 시스템은 FileSystem 인터페이스를 통해서 접근할 수 있다.
FileSystem fileSystem = FileSystems.getDefault(); | FileSystem 구현 객체를 얻을 수 있다. |
Iterable<FileStore> getFileStores() | 드랄이버 정보를 가진 FileStore 객체들을 리턴 |
Iterable<Path> getRootDirectories() | 루트 디렉토리 정보를 가진 Path 객체들을 리턴 |
String getSeparator() | 디렉토리 구분자 리턴 |
long getTotalSpace() | 드라이버 전체 공간 크기(byte 단위) 리턴 |
long getUnallocatedSpace() | 할당되지 않은 공간 크기(byte 단위) 리턴 |
long getUsableSpace() | 사용 가능한 공간 크기, getUnallocatedSpace()와 동일한 값 |
boolean isReadOnly() | 읽기 전용 여부 |
String name() | 드라이버명 리턴 |
String type() | 파일 시스템 종류 |
📌파일 속성 읽기 / 파일 & 디렉토리 생성 및 삭제
long|Path cop(...) | 복사 |
Path createDirectories(...) | 모든 부모 디렉토리 생성 |
Path createDirectory(...) | 경로의 마지막 디렉토리만 생성 |
Path createFile(...) | 파일 생성 |
void delete(...) | 삭제 |
boolean deleteIfExists(...) | 존재한다면 삭제 |
boolean exists(...) | 존재 여부 |
FileStore getFileStore(...) | 파일이 위치한 FileStore(드라이브) 리턴 |
FileTime getLastModifiedTime(...) | 마지막 수정 시간을 리턴 |
UserPrincipal getOwner(...) | 소유자 정보를 리터 |
boolean isDirectory(...) | 디렉토리인지 여부 |
boolean isExecutable(...) | 실행 가능 여부 |
boolean isHidden(...) | 숨김 여부 |
boolean isReadable(...) | 읽기 가능 여부 |
boolean isRegularFile(...) | 일반 파일인지 여부 |
boolean isSameFile(...) | 같은 파일인지 여부 |
boolean isWritable(...) | 쓰기 가능 여부 |
Path move(...) | 파일 이동 |
BufferedReader newBufferedReader(...) | 텍스트 파일을 읽는 BufferedReader 리턴 |
BufferedWirter newBufferedWriter(...) | 텍스트 파일에 쓰는 bufferedWriter 리턴 |
SeekableByteChannel newByteChannel(...) | 파일에 읽고 쓰는 바이트 채널을 리턴 |
DirectoryStream<Path> newDirectoryStream(...) | 디렉토리의 모든 내용을 스트림으로 리턴 |
InputStream newInputStream(...) | 파일의 InputStream 리턴 |
OutputStream newOutputStream(...) | 파일의 OutputStream 리턴 |
boolean notExists(...) | 존재하지 않는지 여부 |
String probeContentType(...) | 파일의 MIME 타입을 리턴 |
byte[] readAllBytes(...) | 파일의 모든 바이트를 읽고 배열로 리턴 |
List<String> readAllLines(...) | 텍스트 파일의 모든 라인을 읽고 리턴 |
long size(...) | 파일의 크기 리턴 |
Path write(...) | 파일에 바이트나 문자열을 저장 |
📌와치 서비스(WatchService)
와치 서비스는 디렉토리 내부에서 파일 생성, 삭제, 수정 등의 내용 변화를 감시하는데 사용된다.
예를 들어 에디터로 파일을 편집하고 있을 때, 에이터 바깥에서 파일 내용이 수정되면 에디터에서 파일 내용이 변경됐으니 다시 파일을 불러올 것인지 묻는 팝업창이 뜬다. 이것이 바로 와치 서비스의 사용 예이다.
WatchService 생성
WatchService watchService = FileSystem.getDefault().newWatchService();
WatchService 등록
WatchService를 생성했다면, 감시가 필요한 디렉토리의 Path 객체에서 register() 메소드로 WatchServcie를 등록하면 된다. 어떤 변화(생성, 삭제, 수정)를 감시할 것인지를 StandardWatchEventKinds 상수로 지정할 수 있다.
path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, //생성
StandardWatchEventKinds.ENTRY_MODIFY, //수정
StandardWatchEventKinds.ENTRY_DELETE); //삭제
WatchKey 얻기
디렉토리(Path)에 WatchService를 등록한 순간부터 디렉토리 내부에서 변경이 발생하면 WatchEvent가 발생하고, WatchService는 해당 이벤트 정보를 가진 WatchKey를 생성하여 Queue에 넣어준다. 프로그램은 무한 루프를 돌면서 WatchService의 task() 메소드를 호출하여 WatchKey가 큐에 들어올 때까지 대기하고 있다가 WatchKey가 큐에 들어오면 WatchKey를 얻어 처리하면 된다.
while(true){
WatchKey watchKey = watchService.take(); //큐에 WatchKey가 들어올 때까지 대기
}
WatchKey를 얻으면 pollEvents() 메소드를 호출해서 WatchEvent 리스트를 얻어낸다.
한 개의 WatchEvent가 아닌 List<WatchEvent<?>>로 리턴하는 이유는 여러 개의 파일이 동시에 생성, 삭제, 수정될 수 있기 때문이다. 물론 WatchEvent는 파일당 하나씩 발생한다.
List<WatchEvent<?>> list = watchKey.pollEvents();
이렇게 해서 얻어낸 WatchEvent 리스트에서 WatchEvent를 하나씩 꺼내어 이벤트의 종류와 Path 객체를 얻어낸 다음 처리하면 된다.
for(WatchEvent watchEvent : list){
//이벤트 종류 얻기
Kind kind = watchEvent.kind();
//감지된 Path 얻기
Path path = (Path)watchEvent.context();
//이벤트 종류별로 처리
if(kind == StandardWatchEventKinds.ENTRY_CREATE){
//생성되었을 경우, 실행할 코드
} else if(kind == StandardWatchEventKinds.ENTRY_DELETE){
//삭제되었을 경우, 실행할 코드
} else if(kind == StandardWatchEventKinds.ENTRY_MODIFY){
//수정되었을 경우, 실행할 코드
} else if(kind == StandardWatchEventKinds.OVERFLOW){
}
OVERFLOW 이벤트는 운영체제에서 이벤트가 소실됐거나 버려진 경우에 발생하므로 별도의 처리 코드가 필요 없다.
WatchService 종료
한 번 사용된 WatchKey는 reset() 메소드로 초기화해야 한다. 새로운 WatchEvent가 발생하면 큐에 다시 들어가기 때문이다. 초기화에 성공하면 reset() 메소드는 true를 리턴하지만, 감시하는 디렉토리가 삭제되었거나 키가 더 이상 유효하지 않을 경우 false를 리턴한다. WatchKey가 더 이상 유요하지 않게 되면 무한 루프를 빠져나와 WatchService의 close() 메소드를 호출하고 종료하면 된다.
while(true){
WatchKey watchKey = watchService.take();
List<WatchEvent<?>> list = watchKey.pollEvents();
for(WatchEvent watchEvent : list){
...
}
boolean valid = watchKey.reset();
if(!valid) {break;}
}
watchService.close();
'Java' 카테고리의 다른 글
[Java] JavaFX 이클립스에 세팅 (0) | 2022.06.07 |
---|---|
[Java] JavaFX 개요 (0) | 2022.06.07 |
[Java] NIO 기반 입출력 - (1)NIO란? (0) | 2022.06.07 |
[Java] TCP 네트워킹 - (4)스레드 병렬 처리 (0) | 2022.06.06 |
[Java] IO 기반 입출력 - (1)입력 스트림과 출력 스트림 (0) | 2022.06.05 |