단일 파일 처리 하는 방법을 적은 게시글에서
기본적으로 사용되는 Path, WatchService, FileChannel 들의 내용을 적어두었다
해당 게시글에서는 기존에 만든 코드에서 복수개로 처리할때
신경쓰고 처리해주어야할 부분에 대해서 적을것이다
전체적인 이해를 위해서는 아래의 게시글을 참고 바란다
https://vuddus526.tistory.com/503
[Java] java.nio 활용 FileTracker 구현 (단일 파일 처리)
1. 개요 2024년에 들어서면서 새로운 프로젝트를 진행하게되었다 전체적인 프로젝트 내용은 모니터링 시스템이다 log 파일에 에러 메세지(log) 가 발생 하는지 모니터링을 하고 발생하면 관리자에
vuddus526.tistory.com
1. 복수 파일 처리시 신경써야할 부분
모든 처리를 for문과 같은 반복문으로 동일하게 동시에 진행해야한다
예를 들어 FileChannel을 open() 할때에도 모든 파일을 열어줘야하고
작업이 끝나도 모든 파일을 다 닫아주어야한다
또한 도중에 하나의 파일이 변경된다면 해당 파일만 뽑아서 처리해줘야한다
이러기 위해서는 기존에는 채널의 id 값만 가지고 처리했지만
채널의 id가 어떤 파일인지 알 수 있게 ArrayList에
HashMap 객체로 넣어 생성할 것이다
private ArrayList<HashMap<Path, FileChannel>> readChannel = new ArrayList<>();
private HashMap<Path, FileChannel> pathFileChannel
this.readChannel.add(this.pathFileChannel);
제네릭을 보면 알 수 잇듯이 key 값으로는 파일의 경로
value는 채널 id를 넣을것인데 key 값은 getFileName() 를 이용해서
파일 경로 대신 파일 이름을 넣어줄것이다
이렇게하면 (Path)event.context(); 을 이용해서
이벤트가 발생했을때 생성이든 삭제든 파일 이름을 얻을 수 있는데
변경된 파일의 이름을 가지고 채널의 id를 알아내고 열고 닫을 수 있어진다
2. 추가된 코드
1) path 처리
기존에는 path 하나만 가지고 처리를 했다면
ArrayList<Path> target 을 만들어서 값을 넣어주고
for 문을 이용해서 채널들을 생성해 준다
private ArrayList<Path> target;
for (int i = 0; i < this.target.size(); i++) { }
2) events 처리
기존 WatchEvent watchEvent 변수를 list로 만든다
왜냐하면 한번에 여러개의 파일이 동시에 변경되었을때
watchKey를 여러개 받아야하기 때문이다
List<WatchEvent<?>> events = watchKey.pollEvents();
3) 특정 channel 처리
기존 채널중 하나가 닫혔을때 해당 채널만을 찾아서
처리하는 로직도 필요하다
이는 앞서 설명했듯이 이벤트 발생할때마다
eventFile이 무엇인지 확인 가능하니
해당 파일이름에 해당하는 readChannel 을 닫고
기존 있던 자리에 새로운 readChannel과 파일이름을 넣어줘야한다
위는 원본 파일은 이름이 변경되고, 파일이 새로 생성될 경우에 나타나는 상황이다
DELETE 발생시 해당하는 파일 이름을 imsiEventFile에 담고
CREATE 발생시 tempReadChannel에 imsiEventFile에 해당하는 채널 id를 뽑아서 담고
기존 readChannel을 닫아주고 새로운 eventFile 과 새로운 채널을 readChannel에 담아준다
이는 아래의 로직처럼 구현할 수 있다
if (kind == StandardWatchEventKinds.ENTRY_DELETE) {
imsiEventFile = eventFile;
}
if (kind == StandardWatchEventKinds.ENTRY_CREATE) {
for (int i = 0; i < this.readChannel.size(); i++) {
FileChannel tempReadChannel = this.readChannel.get(i).get(imsiEventFile);
// 기존 채널 닫음
if (tempReadChannel != null) {
tempReadChannel.close();
tempReadChannel = null;
// 기존 채널 삭제
this.readChannel.remove(i);
this.onlyReadChannel.remove(i);
this.target.remove(i);
// 새로운 채널 추가
this.target.add(i, parentPath.resolve(eventFile));
this.pathFileChannel = new HashMap<>();
this.pathFileChannel.put(eventFile,
FileChannel.open(this.target.get(i), StandardOpenOption.READ));
this.readChannel.add(i, this.pathFileChannel);
this.onlyReadChannel.add(i, this.readChannel.get(i).get(eventFile));
}
}
4) readBuffer 처리
파일을 읽는 작업 또한 for문으로 readChannel 하나씩 봐줘야한다
그렇다고 매번 모든 파일을 보는건 비효율 적이기 때문에
target 파일중 바뀌지 않은 파일은 생략하는 로직도 필요하다
바뀐 eventFile에 해당하지 않으면 continue 해준다
for (int i = 0; i < this.readChannel.size(); i++) {
// target 파일중 바뀌지 않은 파일은 생략
if (this.readChannel.get(i).get(eventFile) == null) {
continue;
}
}
5) channel 닫기
프로그램을 종료 할때에도 모든 채널을 닫을 수 있게 처리해 주어야 한다
// 파일 읽기 채널 닫음
for (int i = 0; i < onlyReadChannel.size(); i++) {
if (this.onlyReadChannel.get(i) != null && this.onlyReadChannel.get(i).isOpen() == true) {
this.onlyReadChannel.get(i).close();
}
}
'Java' 카테고리의 다른 글
[Java] Javadoc 이란? (0) | 2024.08.07 |
---|---|
[Java] java.nio 활용 FileTracker 구현 3 (리팩토링) (0) | 2024.02.21 |
[Java] java.nio 활용 FileTracker 구현 1 (단일 파일 처리) (0) | 2024.02.19 |
[Java] Java volatile 이란? (1) | 2024.02.05 |
[Java] Solace PubSub+ JCSMP, JMS, JAVA API (0) | 2024.01.16 |