2010-11-29 7 views
4

파일의 재귀 복사본을 만들고 있습니다. xcopy /D 복사 프로세스의 일부 파일을 변경해야하므로 최신 파일 대상 파일 (을 사용할 수 없습니다. 바로 xcopy을 사용하십시오.)을 복사하고 싶습니다.File.lastModified() 고통스럽게 천천히!

자바에서는 대상 파일이 소스 파일보다 오래되어 매우 느린지 확인하기 위해 lastModified()을 사용합니다.

  • (아마도 JNI를 사용하여 처리 속도를 높일 수 있습니까?)?
  • 작업을 더 잘 수행 할 수있는 다른 복사 스크립트가 있습니까? (새 파일 복사 + regexp 일부 텍스트 파일 변경)?

마지막으로 수정 한 날짜 (네트워크를 통해 복사)를 확인하는 것보다 시간이 오래 걸리기 때문에 파일을 복사하는 것은 옵션이 아닙니다.

답변

3

왜 그렇게 느린지를 결정해야합니다.

progrma를 실행할 때 프로세스의 CPU 사용률을 알려줍니다. 50 % 이상의 사용자라면 20 % 미만의 사용자가 할 수있는 일이 없으면 프로그램을 최적화 할 수 있어야합니다.

보통이 방법은 검사중인 파일이 메모리가 아닌 디스크에 있기 때문에 속도가 느립니다. 이 경우 디스크 액세스 방법의 속도를 높이거나보다 빠른 드라이브를 확보해야합니다. 예 : 이렇게하면 SSD가 10-100 배 빨라질 수 있습니다.

대량 쿼리가 도움이 될 수 있습니다. lastModified 날짜를 검사하기 위해 여러 스레드를 사용하여이 작업을 수행 할 수 있습니다. 예 : 고정 된 크기의 스레드 풀을 가지고 각 파일에 대한 작업을 추가하십시오. 스레드 풀의 크기는 한 번에 폴링되는 파일 수를 결정합니다.

이렇게하면 OS가 디스크의 레이아웃에 맞게 요청을 다시 정렬 할 수 있습니다. 참고 : 이것은 이론 상으로는 문제가되지 않지만, OS/하드웨어에서 작업 속도를 향상시킬 수 있는지 테스트해야합니다. ;)

+0

스레드 풀 메서드를 사용했습니다. 훨씬 더 빨리! – dacwe

+0

이 접근법이 잘 작동하면 OS는 헤드 이동을 최소화하기 위해 요청을 다시 정렬 할 수 있습니다. 사용 된 일반적인 골재는 http://en.wikipedia.org/wiki/Elevator_algorithm입니다. BTW, Java 프로그램이 파일을 액세스하는 가장 좋은 순서가 무엇인지 알 수는 없습니다. –

0

this 방법을 확인 했습니까?

+0

방금 ​​링크를 업데이트합니다. – ozhan

+0

LastModified()가 느려지고 'FileUtils'가 저를 위해 (마지막으로 수정 한 날짜가 같은 파일을 복사하는 것은 옵션이 아니므로 속도가 더 느립니다) 볼 수 있습니다. – dacwe

1

불행하게도 Java가 lastModified를 검색하는 방식은 느립니다 (기본적으로 정보를 요청할 때 기본적으로 각 파일에 대한 기본 파일 시스템을 쿼리합니다.이 데이터는 listFiles 또는 이와 유사하게 대량로드되지 않습니다).

잠재적으로 대량으로이를 수행하는보다 효율적인 네이티브 프로그램을 호출 할 수 있지만 이러한 솔루션은 배포 할 플랫폼과 밀접하게 관련되어 있습니다.

1

네트워크를 통해이 작업을 수행하는 것으로 상상해보십시오. 그렇지 않으면 복사본에 작은 부분이있을 것입니다. 네트워크 디렉토리 작업이 느리고 불행합니다. 전체 작업을 수행하는 데 소요되는 시간이 최소한이라도 상관없이 항상 특정 크기 임계 값 아래로 파일을 복사 할 수 있습니다.

저는 여기 Kris와 동의하지 않습니다. Java와는 달리 비효율적 인 것은 없으며, 어떤 경우 든 최신 값을 원하기 때문에 실제로 그렇게해야합니다.

+0

예, 당신이 맞았습니다, 네트워크 ...하지만 Peter Lawrey가 옳은 것 같습니다! – dacwe

0

그래서 네트워크 드라이브에서이 문제가 발생했습니다. 아픈. 17000 개 이상의 파일이있는 디렉토리가 있습니다. 로컬 드라이브에서는 마지막으로 수정 한 날짜를 확인하는 데 2 ​​초도 걸리지 않았습니다. 네트워크로 연결된 드라이브에서 58 초가 걸렸다 !!! 물론 내 응용 프로그램은 대화 형 응용 프로그램이므로 일부 불만이 있습니다.

약간의 연구 끝에 나는 프로세스를 크게 개선하기 위해 Windows Kernel32 findfirstfile/findnextfile/findclose를 수행하는 JNI 코드를 구현할 수 있다고 결정했지만 32 비트 및 64 비트 버전 등을 사용했습니다. 그리고 크로스 플랫폼 기능을 잃게됩니다.

여기에 불쾌한 해킹이 있었는데도 그랬습니다. 내 응용 프로그램은 주로 윈도우에서 작동하지만 그렇게하기 위해 제한하지 않으려 고 그래서 내가 다음 않았다. Windows에서 작동하는지 확인하십시오. 그렇다면 로컬 하드 디스크를 사용하고 있는지 확인하십시오. 그렇지 않다면 우리는 해킹 방법을 수행 할 것입니다.

모든 것을 대소 문자를 구분하지 않고 저장했습니다. 아마도 'ABC'와 'abc'파일이있는 디렉토리가있는 다른 OS에 대해서는별로 좋은 아이디어가 아닙니다. 이것을 고려해야 할 경우 새 파일 ("ABC") 및 새 파일 ("abc")을 만든 다음 equals 메서드를 사용하여 비교할 수 있습니다. 윈도우와 같은 대소 문자를 구별하지 않는 파일 시스템에서는 true를 반환하지만 유닉스 시스템에서는 false를 반환합니다.

시간이 조금 걸릴 수도 있지만 네트워크 드라이브에서 58 초에서 1.6 초로 바뀌어 해킹과 함께 살 수 있습니다.

 boolean useJaveDefaultMethod = true; 

    if(System.getProperty("os.name").startsWith("Windows")) 
    { 
     File f2 = f.getParentFile(); 
     while(true) 
     { 
      if(f2.getParentFile() == null) 
      { 
       String s = FileSystemView.getFileSystemView().getSystemTypeDescription(f2); 
       if(FileSystemView.getFileSystemView().isDrive(f2) && "Local Disk".equalsIgnoreCase(s)) 
       { 
        useJaveDefaultMethod = true; 
       } 
       else 
       { 
        useJaveDefaultMethod = false; 
       } 
       break; 
      } 
      f2 = f2.getParentFile(); 
     } 
    } 
    if(!useJaveDefaultMethod) 
    { 
     try 
     { 
      ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/C", "dir " + f.getParent()); 
      pb.redirectErrorStream(true); 
      Process process = pb.start(); 
      InputStreamReader isr = new InputStreamReader(process.getInputStream()); 
      BufferedReader br = new BufferedReader(isr); 

      String line; 
      DateFormat df = new SimpleDateFormat("dd-MMM-yy hh:mm a"); 
      while((line = br.readLine()) != null) 
      { 
       try 
       { 
        Date filedate = df.parse(line); 
        String filename = line.substring(38); 
        dirCache.put(filename.toLowerCase(), filedate.getTime()); 
       } 
       catch(Exception ex) 
       { 

       } 
      } 
      process.waitFor(); 

      Long filetime = dirCache.get(f.getName().toLowerCase()); 
      if(filetime != null) 
       return filetime; 

     } 
     catch(Exception Exception) 
     { 
     } 
    } 

    // this is SO SLOW on a networked drive! 
    long lastModifiedDate = f.lastModified(); 
    dirCache.put(f.getName().toLowerCase(), lastModifiedDate); 

    return lastModifiedDate;