2014-11-07 5 views
1

각 디렉터리에서 가장 최근에 수정 된 파일을 찾는 파일과 디렉터리를 처리하고 있습니다. 코드는 작동하지만 Ruby에 익숙하지 않아 오류를 올바르게 처리하는 데 문제가 있습니다.Find.find에서 예외를 처리하는 방법

나는 각 디렉토리에 대한 내 자신의 기능 newestFile를 호출, 재귀 적 디렉토리 목록을 얻을 수 Find.find를 사용 : 나는 액세스 권한이없는 폴더가

Find.find(ARGV[0]) { |f| 
    if File.directory?(f) 
    newestFile(f) 
    end 
} 

디렉토리 트리에서, 그래서 무시해야합니다 그들과 다음에 가서,하지만 난 "루프"Find.find에 예외 처리를 통합하는 방법을 볼 수 없습니다.

블록 주위에 begin..rescue..end을 넣으려고했으나 루프 처리를 계속할 수 없습니다.

나는 또한이 질문을 발견 : How to continue processing a block in Ruby after an exception?하지만 에서 루프를 처리합니다. 예외 블록 외부에있는 Find.find에 발생한 오류를 복구하려고합니다.

PS D:\dev\ruby\> ruby .\findrecent.rb "M:/main/*" 
C:/Ruby200/lib/ruby/2.0.0/find.rb:51:in `open': Invalid argument - M:/main/<A FOLDER I CAN'T ACCESS> (Errno::EINVAL) 
     from C:/Ruby200/lib/ruby/2.0.0/find.rb:51:in `entries' 
     from C:/Ruby200/lib/ruby/2.0.0/find.rb:51:in `block in find' 
     from C:/Ruby200/lib/ruby/2.0.0/find.rb:42:in `catch' 
     from C:/Ruby200/lib/ruby/2.0.0/find.rb:42:in `find' 
     from ./findrecent.rb:17:in `<main>' 

가 어떻게이 코드에 예외 처리를 추가하려면 :

다음은 오류의 스택 추적입니까?

나는 예외가 생성되는 코드의 모양을했다 및 방법은 다음 블록이 포함되어

if s.directory? then 
    begin 
    fs = Dir.entries(file) 
    rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG 
    next 
    end 
    ... more code 

내가 rescue 오류 목록에 Errno::EINVAL을 추가 된 끔찍한 해킹을 수행합니다. 이제 내 코드가 실행되고 모든 폴더를 통과하지만 Ruby 라이브러리 코드에 그 변경 사항을 남겨 둘 수는 없습니다.

내부적으로 findDir.entries을 사용하고 있으므로 폴더를 직접 처리하기 위해 코드를 다시 작성해야하며 find에 의존하지 않아도됩니다.

다른 종류의 코드를 읽는 것과 같은 종류의 코드 구조에서 오류를 처리하는 방법이 있는지 알고 싶습니다.이 유형의 작고 간결한 코드는 Ruby에서 많이 사용됩니다.

답변

2

newestFile 함수에서이 오류가 발생하거나 File#directory?을 실행하려고합니까? 이 newestFile에 발생하면

당신은 이런 식으로 뭔가를 할 수 있습니다

Find.find(ARGV[0]) do |f| 
    if File.directory?(f) 
    newestFile(f) rescue nil 
    end 
end 

이것은 단지 다음 폴더까지 오류 및 펀트를 무시합니다. 원하는 경우 당신은 또한 몇 가지 더 좋은 출력을 할 수있는 : 당신이 언급 한 것처럼 오류가 발생하는 경우

Find.find(ARGV[0]) do |f| 
    begin 
    if File.directory?(f) 
     newestFile(f) 
    end 
    rescue 
    puts "error accessing: #{f}, you might now have permissions" 
    end 
end 

: 오류가 File#directory?에서 일어나는

Find.find(ARGV[0]) do |f| 
    if File.directory?(f) 
    begin 
     newestFile(f) 
    rescue 
     puts "error accessing: #{f}, you might now have permissions" 
    end 
    end 
end 

경우뿐만 아니라 그 부분을 포장 할 필요가 Find#find 그때 당신은 블록에서 그걸 잡을 수 없습니다. 그것은 그 방법 안에서 일어날 것입니다.

예외의 스택 추적을 붙여서 해당 메소드에서 예외가 발생했는지 확인할 수 있습니까?

나는 그래서 당신은 그 오류를 잡을 수있는 그 능력을 것 Dir#entries 같은과 디렉토리 자신을 통과하는 제안 거라고

편집. 한 가지 흥미로운 점은 명령 줄에서 호출 할 때 *를 사용하면됩니다. 나는 MacOS에서 나는 당신이보고있는 것을 100 % 복제 할 수 없다. 그러나 그것이 내 Mac에서 접근 할 수없는 디렉토리를 가로 지르도록 허용한다면 나는 접근 할 수없는 폴더에 대한 디버그 정보를 출력하지만 계속된다. 에. 만약 다른 폴더에 * 부여하면, 접근 할 수없는 첫 번째 폴더의 오류를 인쇄하는 것 외에는 아무것도하지 않는 것처럼 보입니다.

맥 OS에 대한 내 경험의 한 가지 차이점은 실제로 예외를 throw하지 않고 콘솔에 디버그 정보를 인쇄하는 것입니다. 그러나 폴더에 접근 할 수 없다면 * 만든 것이 포함 된 것이 완전히 멈췄다는 것이 흥미 롭습니다.

+0

스택 추적으로 내 질문을 업데이트했습니다. 불행히도 오류는'Find.find' 코드에서 유래합니다. – Tony

+0

제안 해 주셔서 감사합니다. 당신의 코멘트 "그것은 그 방법 안에서 일어날 것입니다." 나는 더 깊이 조사 할 생각을하게 만들었고, 그래서 나는'find' 코드를보고 내 질문에 더 많이 추가했습니다. – Tony

+0

루비의'찾기 '는 OP가 그것을 사용하고있는 목적을 위해 특별히 작성된 것으로, 디렉토리 계층을 빠르게 탐색하고 기준에 따라 파일이나 디렉토리를 선택적으로 처리합니다. 'Dir.entries'는 좀 더 일반적이고 * 비슷한 방법으로 사용할 수 있지만 더 많은 코드가 생성됩니다. –

1

반응 적이든 사전 적이든 관계없이 작동하지만 사전 테스트를 통해 예외 메커니즘을 트리거하지 않으므로 코드가 조금 더 빨리 실행됩니다.

예외를 처리하기 위해 문제가 발생하기를 기다리는 대신 File 클래스의 owned?grpowned? 메서드를 사용하여 실제로 디렉토리로 변경하거나 파일에 액세스해야하는지 확인할 수 있습니다. File 문서에서 :

grpowned?(file_name) → true or false 

Returns true if the named file exists and the effective group id of the calling process is the owner of the file. Returns false on Windows.

owned?(file_name) → true or false 

Returns true if the named file exists and the effective used id of the calling process is the owner of the file.

는 코드를 같이 할 수 있습니다 의미 :

Find.find(ARGV[0]) do |f| 
    if File.directory?(f) && %w[grpowned? owned?].any?{ |m| File.send(m.to_s, f) } 
    newestFile(f) 
    end 
end 
루비 디렉토리 항목이 디렉토리인지 여부를 확인합니다

여부 그것은 현재 프로세스에 의해 소유되거나 grpowned됩니다. &&이 단락되어 있기 때문에 디렉터리가 아닌 경우 두 번째 테스트 집합이 트리거되지 않습니다.

일부 시스템에서는 공유 리소스가 많은 경우 그룹 권한을 사용하면 먼저 테스트를 거치고 액세스 권한이 true 일 경우 any?이 true를 반환하고 코드가 진행됩니다. 그룹 권한으로 액세스가 허용되지 않아 false가 반환되면 owned?이 파일을 테스트하므로 코드가 건너 뛰거나 newestFile으로 단계적으로 넘어갑니다. 이 두 가지 테스트를 시스템의 설정에 따라 속도를 반대로하십시오. 또는 time ruby /path/to/your/code을 사용하여 코드 하나를 실행 한 다음 두 개를 뒤집어 다시 실행하십시오. 결과 시간을 비교하여 시스템에서 더 빨리 수행 된 시간을 확인하십시오.

프로그램 흐름을 제어하기 위해 예외 처리를 사용하는 것이 좋고 다른 언어가 프로그래밍 스타일에서 다른 것을 선호하는지에 관해 여러 가지 학교가 있습니다. 나에게 뭔가를 할 수 있는지 미리 알기 만하면 코드가 항상 빠르고 안전하게 작동하는 것처럼 보입니다. 그것이 예상대로 불면, 그것은 하나의 일이지만 기대하지 않았던 방식으로 불면, 올바르게 반응하기 위해 예외 처리를하지 않았을 수도 있고, 실제 원인을 가려주는 다른 예외를 유발할 수도 있습니다 . 차라리 상태를 확인하여 상황을 해결할 수 있는지 확인한 다음 모든 시도가 실패하면 예외 처리기를 사용하여 정상적으로 종료 할 수있게하십시오. YMMV.

마지막으로 Ruby에서는 Camelcase를 사용하여 메소드의 이름을 지정하지 않고 snake_case를 사용합니다. snake_case_is_easier toReadThanCamelCase.

+0

나는 이걸로 무언가를하기 전에 소유권을 확인하는 접근 방식을 좋아합니다. – Bala

+0

그것은 "더 친절하고 부드럽게"생각합니다. –

+0

@ theTinMan - 답변 해 주셔서 감사합니다. 나는 또한 당신이 설명하는 것처럼 예외를 피하기를 선호하지만,이 인스턴스에서는 예외가 _ Find_find 메소드에서 _ 발생하므로 블록에서 폴더 접근을 점검 할 수는 없습니다. 'Errno :: EACCES' [Permission denied]에서 복구 할 때 Ruby 라이브러리에 Windows 특정 버그가있을 수 있지만 Errno :: EINVAL [Invalid argument] 예외가 발생합니다. 나는'find'에서 반환 된 열거자를 사용하려고 시도하고 (블록을 ​​통과시키지 않을 수도 있습니다) 또는'Dir.entries'를 사용하고, 다른 주석에서 말했듯이, 코드가 부 풀려서 살고 있습니다. – Tony

관련 문제