2013년 9월 15일 일요일

자바7 NIO.2 - 내용정리 5장

chapter 5. 재귀 작업:Walk

파일에 관련에 프로그램밍은 재귀적인 적당하다. 즉 파일 트리 삭제, 복사, 이동에서 흔하게 사용될 수 있다.
NIO.2에서 파일 트리의 순회traversal process 캡슐화 하여 java.nio.file.FileVisitor 인터페이스로 나타냄.

5.1 FileVisitor 인터페이스

접근 전, 접근 중, 접근 후 , 접근 이 실패했을 때를 위한 Hook을 제공한다. 이것을 이용해서 파일을 처리할 수 있다.
즉 관련 상태를 보고 어떻게 처리할지 선택, 무엇을 할지 결정할 수 있음.
그 결과를 FileVisitResult enum으로 알 수 있다.
FileVisitResult 상수 값
  • CONTINUE : 순회 과정이 계속 진행 중인 상태
  • SKIP_SIBLINGS : 방문 중인 파일이나 디렉토리의 형제를 방문하지 않아도 순회 과정은 지속된다.
  • SKIP_SUBTREE : 방문 중인 디렉토리의 다른 항목을 방문하지 않아도 순회 과정이 지속된다.
  • TERMINATE : 순회 과정이 종료 되어야 한다.

5.1.1 FileVisitor.visitFile() 메소드
디렉토리에 있는 파일에 대해 호출된다. 보통 CONTINUE나 TERMINATE를 결과로 반환한다. 예를 들면 어떻 파일을 찾을 때까지는 CONTINUE, 파일을 발견한 다음에는 TERMINATE를 반환 한다.
메서드 서명
FileVisitResult visitFile(T file,BasiceFileAttributes attrs) throws IOEXception

5.1.2 FileVisitor.preVisitDirectory() 메소드
디렉토리에 있는 항목을 방문하기 전에 디렉토리에 대해 호출된다.
반환 결과
  • CONTINUE 반환 : 항목을 방문
  • SKIP_SUBTREE 반환 : 항목을 방문하지 않는다.
  • SKIP_SIBLINGS 결과 반환 : 방문 중인 파일이나 디렉토리의 형제를 방문하지 않는다.
FileVisitResult preVisitDirectory(T dir,BasiceFileAttributes attrs) throws IOEXception

5.1.3 FileVisitor.postVisitDirectory() 메소드
디렉토리에 있는 항목(후손까지)을 모두 방문하거나(IO 에러 발생해서 중단 시킨 경우) 방문이 갑자기 중단된 후에 호출된다. 인자 IOException은 방문하는 에러가 없다면 nul 이다.
FileVisitResult postVisitDirectory(T dir,IOException exc) throws IOEXception

5.1.4 FileVisitor.visitFileFailed() 메소드
파일을 어떤 이유로 접근할 수 없을 때 호출.
FileVisitResult visitFileFailed(T file,IOException exc) throws IOEXception

5.2 SimpleFileVisitor 클래스

이미 FileVisitor의 모든 메소드를 구현한 클래스, 일반적으로 이것을 상속에서 사용한다.

5.3 재귀 처리

Files.walkFileTree() 메소드를 호출해서 프로세스를 시작한다.

5.4 공통 작업 : Walk

5.4.1 파일 검색 애플리케이션 작성하기
FileVisitor 기반의 검색 도구 작성시 기억해야 하는 사항
  • visitFile() 메서드가 현재 파일과 검색 범위 사이를 비교하기에 가장 좋은 위치이다. 이 시점에 개별의 파일의 이름 확장자, 속성을 추출하거나 읽기 위해 파일을 열 수 있다. 파일 이름, 확장자등을 사용해서 방문한 파일이 검색하려는 파일인지 결정할 수 있다. 이런 정보를 조합해서 복잡한 검색 조건을 지정할 수 있다. 단 이 메소드는 디렉토리는 찾지 않는다.
  • 디렉토리를 찾고 싶다면 preVisitDirectory() 나 postVisitDirectory() 메소드에서 비교를 수행해야 한다. 어떤 메소드를 선택하는 가는 경우에 따라 틀림.
  • 파일을 방문할 수 없더라도 문제가 전체 검색 처리를 중단해야 하는 것이 아니므로 visitFileFailed() 메소드는 FileVisitResult.CONTINUE를 반환 해야 한다.
  • 파일 이름으로 검색을 한다면 파일 트리에 해당 이름으로 된 파일이 하나만 있다는 사실을 알아야 한다. 그러므로 visitFile() 메소드에서 파일을 찾았다면 FileVisitResult.TERMINATE를 반환 해야 한다. 그렇지 않은 경우엔 FileVisitResult.CONTINUE를 반환해야 한다.
  • 검색 과정에서 심볼 링크를 따라가는 것은 좋은 생각이다. 심볼 링크를 따라가면 심볼링크가 가리키는 대상의 서브 트리를 순회하기 전에 검색하려는 파일이 있을 수도 있기 때문이다. 그렇다고 심볼 링크를 따라가는 것이 항상 좋은 것은 아니다. 예를 들어 파일 삭제를 할 때는 심볼 링크를 따라가지 않는 게 좋다.

5.4.2 파일 삭제 애플리케이션 작성하기
FileVisitor구현을 통해서 delete() 혹은 deleteIfExist() 구현시 주의 사항
  • 디렉토리를 삭제하기전에 디렉토리에 있는 파일은 반드시 모두 삭제해야 한다.
  • visitFile() 메서드가 개별 파일을 삭제하기에 가장 좋은 위치이다.
  • 디렉토리가 비어 있을 때만 디렉토리를 삭제할 수 있으므로 postVisitDirectory() 메소드에서 디렉토리를 삭제하는 것이 좋다.
  • 파일을 방문할 수 없다면 visitFileFailed() 메소드는 상황에 따라 FileVisitResult.CONTINUE 나 FileVisitResult.TERMINATE를 반환해야 한다.
  • 삭제 처리에 심볼 링크를 따를 수 있지만, 심볼 링크는 종종 삭제 영역 바깥의 파일을 가리키므로 권장하지 않는다. 심볼 링크가 삭제 영역을 절대로 벗어나지 않는다고 확신하거나 충분한 조건을 통해 바람직하지 않는 삭제가 일어나지 않는다고 확신한다면 심볼링크를 따라 갈 수 있다.

** 삭제된 파일을 휴지통으로 보내는 작업은 JNI를 사용해서 Window API SHFileOperation() 메소드를 호출해서 수행할 수 있다. 관련 내용은 다음 참고

5.4.3 파일 복사 애플리케이션 작성하기
주의 사항
  • 디렉토리에서 파일을 복사하기 전에 디렉토리 부터 복사해야 한다. 원본 디렉토리를 복사하면 비어 있는 대상 디렉토리가 만들어 진다. 이 작업은 반드시 preVisitDirectory() 메소드에서 수행해야 한다.
  • visitFile() 메소드가 개별 파일을 복사하기에 가장 좋은 위치다.
  • 파일이나 디렉토리를 복사할 때 REPLACE_EXISTING 과 COPY_ATTRIBUTE 옵션 사용 여부를 결정해야 한다.
  • 원본 디렉토리의 속성을 보존하고 싶다면 파일을 복사한 다름에 postVisitDirectory() 메서드에서 작업을 수행해야 한다.
  • 링크를 따라 가지(FOLLOW_LINKS)로 결정했고, 파일 트리에 부모 디렉토리의 순환 링크가 있다면 visitFileFailed() 메서드에서 FileSystemLoopException 예외와 함께 루프 디렉토리가 보고된다.
  • 파일을 방문할 수 없다면 visitFileFailed() 메서드는 상황에 따라 FileVisitResult.CONTINUE나 FileVisitResult.TERMINATE를 반환해야 한다.
  • 복사과정은 FOLLOW_LINKS 옵션을 지정한 경우에만 링크를 따라간다.

5.4..4 파일 이동 애플리케이션 작성하기
파일 트리 이동은 파일 트리 복사와 삭제를 애플리케이션 하나로 결합한 작업이다.
실제로 파일 트리 이동에는 두 가지 방법
  • Files.move(), Files.copy() 와 Files.delete() 조합
  • Files.copy()와 Files().delete()
주의사항

  • 디렉토리에서 파일을 이동하기 전에 디렉토리 자체를 이동해야 한다. 비어 있지 않는 디렉토리는 이동할 수 없으므로 Flies.copy() 메서드를 사용해야 한다. Files.copy() 메서드는 비어 있는 디렉토리를 복사 할 것이다. 이 작업은 preVisitDirectory() 메서드에서 수행 되어야 한다.
  • visitFile() 메서드가 개별 파일을 이동하기에 가장 좋은 위치다. 이 작업을 위해 Files.move() 메서드를 사용하거나 Files.copy()와 Files.delete() 메서드를 조합해서 사용할 수 있다.
  • 원본 디렉토리의 모든 파일을 대상 디렉토리로 이동한 후에는 Files.delete() 메서드를 호출해서 원본 디렉토리를 삭제해야 한다. 이 때는 원본 디렉토리가 비어 있어야 한다. 이 작업은 반드시 postVisitDirectory() 메서드에서 수행 해야 한다.
  • 파일이나 디렉토리를 복사할 때  REPLACE_EXISTING 과 COPY_ATTRIBUTE 옵션 사용 여부를 결정해야 한다. 또한, 파일이나 디렉토리를 이동할 때 ATOMIC_MOVE가 필요한지도 결정해야 한다.
  • 원본 디렉토리의 속성을 보존하고 싶다면 파일을 이동한 다음에 postVisitDirectory()에서 작업을 수행해야 한다. lastModifiedTime 같은 일부 속성은 preVisitDirectory() 메서드에서 추출해서 postVisitDirectory() 메소드에서 설정할 때까지 값을 저장하고 있어야 한다. 원본 디렉토리에서 파일을 이동한 후에는 디렉토리 내용이 바뀌고 처음의 수정일도 새로운 날짜로 덮어써지므로 이처럼 처리해야 한다.
  • 파일을 방문할 수 없다면 visitFileFailed() 메서드는 상황에 따라 FileVisitResult.CONTINUE나 FileVisitResult.TERMINATE를 반환해야 한다.
  • 이동 과정은 FOLLOW_LINKS 옵션을 지정한 경우에만 링크를 따라간다. 심볼 링크 이동은 링크가 가리키는 대상이 아니라 링크 자체를 이동하는 것임을 명심하자.

    - 참고 문헌 : 한빛미디어 , 자바7 NIO.2 파일&네트워크 프로그램밍

댓글 없음: