2011-12-12 2 views
23

파일 감시자를 구현했지만 java nio 파일 감시자가 매핑 된 드라이브에 복사되는 파일에 대한 이벤트를 생성하지 못하는 것으로 나타났습니다. 예를 들어 유닉스에서 파일 감시자를 실행하여 로컬 디렉토리 (/sharedfolder)를 윈도우 (H:\)에 매핑 한 다음이 디렉토리 (H:\)에 파일을 넣었지만 파일 감시자는 그렇지 않습니다. 모든 이벤트가 생성되었습니다. 이제 유닉스 경로 (/sharedfolder)를 참조하는 맵핑 된 드라이브 (H:\)와 unix에서 파일을이 폴더에 넣으면 파일 감시자가 변경 사항을 확인하고 이벤트를 생성합니다. 그것은 버그처럼 보이거나, 어떤 생각이나, 어떤 생각을 놓치고있는 것일 수 있습니까?Java WatchService가 매핑 된 드라이브를 보면서 이벤트를 생성하지 않음

답변

4

JDK의 파일 감시 기능은 기본 라이브러리를 사용하므로 플랫폼에 따라 다르므로 다른 플랫폼에서 다르게 동작 할 수 있습니다. 나는 그것이 네트워크 드라이브를 위해 일하는 것에 전혀 놀랐다 - 리눅스는 리눅스가 (정당하게 그렇게 말해야한다) 동안 변경을 위해 네트워크 매핑 된 드라이브를 폴링해야한다.

보통 이러한 종류의 모니터링은 OS 커널에 구현되었으며 파일은 수정/생성 된/로컬에 대한 지식이 있지만 OS가 배타적 제어가 없으므로 네트워크 드라이브에서 어떤 일이 발생했는지 쉽게 알 수 없습니다 그걸로.

+0

그래,하지만보고있는 디렉토리는 내가 감시자를 돌리고있는 동일한 컴퓨터에 있습니다. 따라서 전송은 네트워크 또는 로컬 컴퓨터를 통해 이루어 지므로 os는이를 인식하고 그렇지 않은 경우 전송을 수행 할 수 있어야합니다. Windows가 매핑 된 드라이브를 폴링하는 것은 당연한 일이지만 Unix가 로컬 폴더의 네트워크를 통해 이루어진 변경을 인식하지 못하는 이유를 이해하지 못합니다. – Ramcis

+0

@Ramcis : Linux 네트워크 공유는 NFS를 통해 마운트되며 NFS는 설계 상 상태가없는 프로토콜입니다. 따라서 서버는 얼마나 많은 클라이언트가 어떤 파일에 액세스하고 있는지 모릅니다. 디자인은 몇 가지 이점 (예 : 오버 헤드 감소)과 몇 가지 단점을 가지고 있습니다 ... – Robert

1

필자는 원격 Windows 디렉터리에서 로그 파일의 내용을 보는 Python 스크립트와 비슷한 문제가있었습니다.

여기 내 대답입니다.

/etc/fstab 사용 //xxx.xxx.xxx.xxx/shareddrive /media/shareddrive cifs username=xxxx,password=xxxx,**directio** 0 0

당신은 자격 증명을 일반 텍스트 암호를 피하기 위해 파일을 사용할 수 있습니다에, 유닉스에서 원격 드라이브를 매핑.

이 명령은 유닉스 버전에 따라 달라질 수 있습니다. 이것은 debian에서 테스트되었습니다. 의도 한대로 작동해야합니다. 작동하는지 말해 줄 수 있습니까? 나는 Java에서 같은 것을 구현하기 때문에 그 해답이 나에게도 유용 할 것이다.

+0

더 이상 작동하지 않습니다. 나는 우분투에서 어쨌든 우연히 다소 벗겨지는 방식으로 작동한다고 생각하지만, 최근 업데이트 후에는 완전히 작동을 멈췄다. 나는 끔찍한 해결 방법을 설명하는 대답을 추가했다. – rubyruy

20

동일한 문제가 CIFS를 통해 마운트 된 Windows 공유를 보려고합니다. filesystem events for CIFS mounts을 얻을 수없는 것 같습니다.

Java 7 NIO FileWatcher의 linux 구현은 inotify을 사용합니다. Inotify는 리눅스 커널 서브 시스템으로 로컬 디렉토리에 대해 완벽하게 작동하는 파일 시스템 변경을 알 수 있지만 분명히 CIFS mounts은 아닙니다.

오라클에서는 this bug을 수정하는 것이 우선 순위가 높지 않습니다. (그것은 자신의 책임인가?하는 OS 문제의 더 ...)

JNotify는 리눅스 시스템에서 inotify를 사용하기 때문에이 중 어떤 옵션이 없습니다.

그래서 매핑 된 드라이브 모니터링은 불행하게도 폴러로 제한 될 것으로 보인다 :

  • Apache VFS DefaultFileMonitor 디렉토리 (마운트 주) 표준 자바 API를 기반으로
  • 파일 폴러를 폴링 할 수 있습니다.이 파일 생성, 업데이트를 감지에서 삭제하기 때문에 jCIFS
  • 사용자 정의 파일 폴러는

아마 아파치 VFS 모니터를 시도 할 것이다 (그래서 공유는 호스트에 장착 할 필요가 없습니다) 상자. 공유를 마운트해야하지만 OS가 CIFS 연결에 책임이 있으며 응용 프로그램에는 책임이 없습니다.

1

나는 이것에 또한 달려 들고 다른 모든 사람들과 같은 결론에 도달했다 (CIFS + inotify = no go).

그러나 워크 플로가 inotify에 의존하는 원격 마운트와 자동 컴파일 도구에 의존하기 때문에 기본적으로 폴링을 사용하여 변경 사항을 확인한 후 접촉하는 솔루션 (상당히 까다로운 & 해킹)을 작성했습니다. 장착 된 쪽에서 같은 파일을 다시 읽습니다. 으로 인해 inotify 이벤트가 실행되지 않는 것 같습니다. 그것은 나의 가장 자랑스러운 순간이 아니다.

는 작업을 수행하므로, 즐길했다 가졌 :

1

http://github.com/rubyruy/watchntouch 내가 같은 문제가 있었다. 주 클래스에서 새 스레드를 만들고 파일을 주기적으로 만져서 새로운 변경 이벤트가 시작되면이를 해결했습니다.

샘플은 10 초마다 dir을 폴링합니다.

package com.ardevco.files; 

import java.io.IOException; 
import java.nio.file.DirectoryStream; 
import java.nio.file.Files; 
import java.nio.file.Path; 
import java.nio.file.Paths; 
import java.nio.file.attribute.FileTime; 
import java.util.ArrayList; 
import java.util.List; 

public class Touch implements Runnable { 

    private Path touchPath; 

    public Touch(Path touchPath) { 
     this.touchPath = touchPath; 
     this.checkPath = checkPath; 

    } 

    public static void touch(Path file) throws IOException { 
     long timestamp = System.currentTimeMillis(); 
     touch(file, timestamp); 
    } 

    public static void touch(Path file, long timestamp) throws IOException { 
     if (Files.exists(file)) { 
      FileTime ft = FileTime.fromMillis(timestamp); 
      Files.setLastModifiedTime(file, ft); 
     } 
    } 

    List<Path> listFiles(Path path) throws IOException { 
     final List<Path> files = new ArrayList<>(); 
     try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) { 
      for (Path entry : stream) { 
       if (Files.isDirectory(entry)) { 
        files.addAll(listFiles(entry)); 
       } 
       files.add(entry); 
      } 
     } 
     return files; 
    } 

    @Override 
    public void run() { 
     while (true) { 
      try { 
       for (Path path : listFiles(touchPath)) { 
        touch(path); 
       } 
      } catch (IOException e) { 
       System.out.println("Exception: " + e); 
      } 

      try { 
       Thread.sleep(10000L); 
      } catch (InterruptedException e) { 
       System.out.println("Exception: " + e); 
      } 
     } 

    } 

} 
관련 문제