Ruby의 File.open과 f.close의 필요성


92

대부분의 프로그래밍 언어에서 파일 작업의 흐름은 개방-사용-폐쇄라는 것은 상식입니다. 하지만 필자는 루비 코드에서 필적 할 수없는 File.open 호출을 여러 번 보았고, 또한 루비 문서 에서이 지식의 보석을 발견 했습니다 .

I / O 스트림은 가비지 수집기에서 요청하면 자동으로 닫힙니다.

darkredandyellow 친화적 인 irc가 문제를 해결합니다.
[17:12] 예, 또한 파일 설명 자의 수는 일반적으로 OS에 의해 제한됩니다.
[17:29] 가비지 수집기가 정리 되기 전에 사용 가능한 파일 설명자가 쉽게 부족할 수 있다고 가정 합니다. 쪽으로. 이 경우 직접 close를 사용하는 것이 좋습니다. "가비지 수집기에 의해 요구됩니다." GC가 미래의 어느 시점에서 작동 함을 의미합니다. 그리고 비싸다. 명시 적으로 파일을 닫는 데는 많은 이유가 있습니다.

  1. 명시 적으로 닫아야합니까?
  2. 그렇다면 GC가 자동으로 닫히는 이유는 무엇입니까?
  3. 그렇지 않다면 왜 옵션입니까?

1
당신의 '상식'은 소멸자가 발명 된 이후로 구식입니다.
meagar

1
@meager : 소멸자는 언제 발명 되었습니까?
Andrew Grimm 2011 년

참고 : 파일 설명자는 제한적이지만 Linux에서는 최소한 제한이 상당히 높습니다.
Linuxios

1
@Linuxios : 내 우분투 12.04 $ ulimit -n => 1024에서는 간단한 일을 할 때만 높습니다. 나쁜 습관은 언젠가 큰 문제를 일으킬 것입니다!
HVNSweeting

답변:


133

나는 루비 코드에서 타의 추종을 불허하는 File.open호출 에서 여러 번 보았다

예를 들어 줄 수 있습니까? 나는 "파일 작업을위한 흐름이 개방-사용- 폐쇄적 이라는"대부분의 프로그래밍 언어에 대한 상식이 부족한 초보자가 작성한 코드에서만 볼 수 있습니다.

숙련 된 Rubyists는 파일을 명시 적으로 닫거나, 더 관용적 File.open으로는 파일을 자동으로 닫는 블록 형식을 사용 합니다. 구현은 기본적으로 다음과 같습니다.

def File.open(*args, &block)
  return open_with_block(*args, &block) if block_given?
  open_without_block(*args)
end

def File.open_without_block(*args)
  # do whatever ...
end

def File.open_with_block(*args)
  yield f = open_without_block(*args)
ensure
  f.close
end

스크립트는 특별한 경우입니다. 스크립트는 일반적으로 너무 짧게 실행되며 스크립트가 종료 될 때 운영 체제가 닫을 것이기 때문에 파일 설명자를 너무 적게 사용하여 닫는 것이 의미가 없습니다.

명시 적으로 닫아야합니까?

예.

그렇다면 GC가 자동으로 닫히는 이유는 무엇입니까?

객체를 수집 한 후에는 더 이상 파일을 닫을 방법이 없으므로 파일 설명자가 유출 될 수 있습니다.

파일을 닫는 것은 가비지 수집기가 아닙니다. 가비지 수집기는 개체를 수집하기 전에 개체에 대한 종료자를 실행합니다. 그냥 그렇게하는 것이 어떻게 File클래스 파일을 닫습니다 파이널 라이저를 정의합니다.

그렇지 않다면 왜 옵션입니까?

낭비되는 메모리는 저렴하지만 낭비되는 파일 설명자는 그렇지 않기 때문입니다. 따라서 파일 설명 자의 수명을 일부 메모리 청크의 수명과 연결하는 것은 의미가 없습니다.

당신은 단순히 예측할 수 없습니다 가비지 수집기가 실행됩니다. 당신도 예측할 수없는 경우 가 실행됩니다 전혀 : 당신이 메모리가 부족하지 않을 경우, 가비지 컬렉터가 실행되지 않습니다, 그러므로 파이널이 실행되지 않습니다 따라서 파일이 폐쇄되지 않습니다.


1
github.com/isaac/sunspot/blob/cell/sunspot/lib/sunspot/… +23 (Kernel # open이 주로 HTTP 측에 사용되었지만 그럼에도 불구하고 로컬 파일 경로 매개 변수로 도달했습니다. ..; 여전히 패치 & 요청-풀할 시간을 찾으려고합니다), github.com/jnicklas/carrierwave Ctrl + f "File.open"(예시로 제공되지만 나쁜 방식으로 ...) 내가 기억하지 못하는 다른 장소. 내 프로젝트의 안정성 요구 사항 때문에 문제가있는 쇠고기가 있습니다.
clyfe

3
이 예에서 레이즈는 구조 블록 안에 있어야합니까? raise가 호출되고 예외가 없으면 런타임 오류가 발생하지 않습니까?
Jeff Storey

@JeffStorey : 좋은 캐치! 17 개월 눈에 띄지 않는…
Jörg W Mittag

@ JörgWMittag 지금은 17 개월 이상하지 고정 : PI는 여기에 주요 포인트는 추측 ensure, rescue그리고 raise전혀 필요하지 않습니다.
KL-7

나는 당신이 ensure없이는 가질 수 없다고 생각합니다 rescue. 그리고 예외를 조용히 삼킬 수는 없습니다. 파일을 닫은 후 호출자에게 전파해야합니다. 어쨌든, 월 다시 '15 - D를 생각 나게
요 르그 W MITTAG

72

사용 후에는 항상 파일 설명자를 닫아야합니다. 종종 사람들은 파일 설명자 수명을 처리하기 위해 File.open 또는 블록이있는 동등한 메서드를 사용합니다. 예를 들면 :

File.open('foo', 'w') do |f|
    f.write "bar"
end

이 예에서는 파일이 자동으로 닫힙니다.


좋은 지적. File.close를 호출하지 않는 스크립트에 대한 버그를 추적했습니다. 결과적으로 마지막 줄은 때때로 일부 파일에서 누락됩니다.
유안 르 그랑

훌륭해. 나는이 속임수를 몰랐다. 그 점에서 java-8과 매우 비슷합니다. 감사합니다.
sagneta

2

http://ruby-doc.org/core-2.1.4/File.html#method-c-open 에 따르면

연관된 블록이없는 File.open은 :: new의 동의어입니다. 선택적 코드 블록이 제공되면 열린 파일이 인수로 전달되고 File 객체는 블록이 종료 될 때 자동으로 닫힙니다. 블록 값은 File.open에서 반환됩니다.

따라서, 블록이 종료되면 자동으로 닫힙니다 .D


1
  1. 그렇지 않은 경우 또는 다른 실패가있는 경우
  2. 2를 참조하십시오.

-3

File.read()함수를 사용하여 ruby ..... 파일을 읽을 수 있습니다.

file_variable = File.read("filename.txt")

이 예 file_variable에서는 해당 파일의 전체 값을 가질 수 있습니다 ....

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.