Ruby에서 파일을 읽는 일반적인 방법은 무엇입니까?


280

Ruby에서 파일을 읽는 일반적인 방법은 무엇입니까?

예를 들어, 여기에 한 가지 방법이 있습니다.

fileObj = File.new($fileName, "r")
while (line = fileObj.gets)
  puts(line)
end
fileObj.close

Ruby가 매우 유연하다는 것을 알고 있습니다. 각 접근 방식의 장점 / 단점은 무엇입니까?


6
현재의 우승 답변이 맞지 않다고 생각합니다.
inger

답변:


259
File.open("my/file/path", "r") do |f|
  f.each_line do |line|
    puts line
  end
end
# File is closed automatically at end of block

위와 같이 한 후에 파일을 명시 적으로 닫을 수도 있습니다 (블록을 ​​전달하여 open닫습니다).

f = File.open("my/file/path", "r")
f.each_line do |line|
  puts line
end
f.close

14
이것은 관용적 인 루비가 아닙니다. 블록 foreach대신 사용하고 사용 하지 open마십시오 each_line.
틴 맨

7
f.each { |line| ... }f.each_line { |line| ... }(루비 2.0.0 적어도) 같은 동작을 갖고있는 것 같다.
chbrown

327

파일이 너무 길지 않은 경우 가장 쉬운 방법은 다음과 같습니다.

puts File.read(file_name)

실제로 IO.read또는 File.read자동으로 파일을 닫으므로 File.open블록과 함께 사용할 필요가 없습니다 .


16
IO.read또는 File.read자동으로 파일을 닫습니다.
Phrogz

15
그는 이미 "파일이 너무 길지 않다"고 말했다. 내 경우에 완벽하게 맞습니다.
jayP 2016 년

227

"슬러그"파일에주의하십시오. 그때 전체 파일을 한 번에 메모리로 읽습니다.

문제는 확장 성이 좋지 않다는 것입니다. 합리적인 크기의 파일로 코드를 개발 한 다음 프로덕션 환경에 넣고 갑자기 기가 바이트로 측정되는 파일을 읽으려고 시도하고 호스트가 메모리를 읽고 할당하려고 시도함에 따라 호스트가 멈추고있는 것을 발견 할 수 있습니다.

라인 별 I / O는 매우 빠르며 거의 항상 slurping만큼 효과적입니다. 실제로 놀랍도록 빠릅니다.

나는 사용하고 싶다 :

IO.foreach("testfile") {|x| print "GOT ", x }

또는

File.foreach('testfile') {|x| print "GOT", x }

파일은 IO에서 상속되며 IO에 foreach있으므로 둘 중 하나를 사용할 수 있습니다.

"파일을"끄는 "이 좋은 방법이 아닌 이유"read 에서 줄 단위 I / O를 통해 큰 파일을 읽는 데 따른 영향을 보여주는 벤치 마크 결과가 있습니다.


6
이것이 바로 내가 찾던 것입니다. 5 백만 줄의 파일이 있는데 실제로 메모리에로드하고 싶지 않았습니다.
Scotty C.

68

한 번에 파일을 읽을 수 있습니다.

content = File.readlines 'file.txt'
content.each_with_index{|line, i| puts "#{i+1}: #{line}"}

파일이 크거나 크면 대개 한 줄씩 처리하는 것이 좋습니다.

File.foreach( 'file.txt' ) do |line|
  puts line
end

때로는 파일 핸들에 액세스하거나 읽기를 직접 제어하려는 경우가 있습니다.

File.open( 'file.txt' ) do |f|
  loop do
    break if not line = f.gets
    puts "#{f.lineno}: #{line}"
  end
end

이진 파일의 경우 다음과 같이 nil-separator와 블록 크기를 지정할 수 있습니다.

File.open('file.bin', 'rb') do |f|
  loop do
    break if not buf = f.gets(nil, 80)
    puts buf.unpack('H*')
  end
end

마지막으로 여러 파일을 동시에 처리 할 때와 같이 블록없이 수행 할 수 있습니다. 이 경우 파일을 명시 적으로 닫아야합니다 (@antinome의 설명에 따라 개선).

begin
  f = File.open 'file.txt'
  while line = f.gets
    puts line
  end
ensure
  f.close
end

참고 : 파일 APIIO의 API .


2
for_each파일 또는 IO 가 없습니다 . foreach대신 사용하십시오 .
Tin Man

1
필자는 여기에 답변에 사용될 코드를 문서화 할 때 RubyMarkers 플러그인과 함께 Sublime Text 편집기를 사용합니다. IRB를 사용하는 것과 유사한 중간 결과를 실제로 표시하기가 쉽습니다. Sublime Text 2 용 Seeing Is Berelieing 플러그인도 정말 강력합니다.
Tin Man

1
좋은 대답입니다. 마지막 예제 에서는 예외가 발생하더라도 파일을 닫는 while대신 사용 loop하고 사용 ensure하는 것이 좋습니다 . 이와 같이 (세미콜론을 개행 문자로 대체) : begin; f = File.open('testfile'); while line = f.gets; puts line; end; ensure; f.close; end.
antinome

1
네, @antinome가 훨씬 나아지고 대답이 향상되었습니다. 감사!
Victor Klos

26

간단한 방법 중 하나를 사용하는 것입니다 readlines.

my_array = IO.readlines('filename.txt')

입력 파일의 각 줄은 배열의 항목이됩니다. 이 메소드는 파일 열기 및 닫기를 처리합니다.


5
read또는 다른 변형 과 마찬가지로 전체 파일을 메모리로 가져 오므로 파일이 사용 가능한 메모리보다 큰 경우 큰 문제가 발생할 수 있습니다. 또한 배열이기 때문에 Ruby는 배열을 작성해야하므로 프로세스 속도가 느려집니다.
Tin Man


9

나는 보통 이것을한다 :

open(path_in_string, &:read)

이것은 전체 텍스트를 문자열 객체로 제공합니다. Ruby 1.9에서만 작동합니다.


이것은 좋고 짧습니다! 파일도 닫습니까?
mrgreenfur

5
닫히지 만 확장 할 수 없으므로주의하십시오.
Tin Man

3

your_file.log 또는 .txt에서 마지막 n 줄을 반환

path = File.join(Rails.root, 'your_folder','your_file.log')

last_100_lines = `tail -n 100 #{path}`

1

보다 효율적인 방법은 운영 체제의 커널에 파일을 열고 비트 단위로 바이트를 읽도록 요청하여 스트리밍하는 것입니다. Ruby에서 라인 당 파일을 읽을 때 한 번에 512 바이트 파일에서 데이터를 가져 와서 그 후 "라인"으로 분할합니다.

파일 내용을 버퍼링하면 파일을 논리적 청크로 나누면서 I / O 호출 수가 줄어 듭니다.

예:

이 클래스를 앱에 서비스 객체로 추가하십시오.

class MyIO
  def initialize(filename)
    fd = IO.sysopen(filename)
    @io = IO.new(fd)
    @buffer = ""
  end

  def each(&block)
    @buffer << @io.sysread(512) until @buffer.include?($/)

    line, @buffer = @buffer.split($/, 2)

    block.call(line)
    each(&block)
  rescue EOFError
    @io.close
 end
end

그것을 호출하고 :each메소드를 블록에 전달하십시오 .

filename = './somewhere/large-file-4gb.txt'
MyIO.new(filename).each{|x| puts x }

이 자세한 게시물에서 여기를 읽으십시오.

AppSignal의 Ruby Magic Slurping & Streaming 파일


조심하십시오 : 그 코드는 줄 바꿈으로 끝나지 않으면 마지막 줄을 무시합니다 (적어도 Linux에서는).
Jorgen

"@ io.close"앞에 "block.call (@buffer)"을 삽입하면 누락 된 불완전한 줄이 나타납니다. 그러나 나는 하루 만 Ruby를 가지고 놀았 기 때문에 틀릴 수 있었다. 그것은 내 응용 프로그램에서 작동했습니다 :)
Jorgen

AppSignal 게시물을 읽은 후 여기에 약간의 오해가있는 것으로 보입니다. 버퍼링 된 IO를 수행하는 게시물에서 복사 한 코드는 Ruby가 File.foreach 또는 IO.foreach (동일한 방법)로 실제로 수행하는 작업의 예제 구현입니다. 그것들을 사용해야하며, 이와 같이 다시 구현할 필요가 없습니다.
피터 H. 볼링

@ PeterH.Boling 나는 또한 대부분의 시간을 사용하고 다시 구현하지 않는 마음가짐을 가지고 있습니다. 그러나 루비는 우리가 물건을 열어서 부끄러워하지 않고 내부를 찌를 수있게 해줍니다. 루비 / 레일에는 실제 'should'또는 'should not'이 없습니다. 무엇을하고 있는지 알고 테스트를 작성하는 한.
Khalil Gharbaoui

0
content = `cat file`

이 방법이 가장 "흔하지 않은"방법이라고 생각합니다. 어쩌면 까다 롭지 만 cat설치되어 있으면 작동합니다 .


1
편리한 트릭이지만 셸을 호출하면 1) 명령이 OS마다 다를 수 있습니다 .2) 파일 이름에서 공백을 이스케이프해야 할 수도 있습니다. Ruby 내장 함수를 사용하는 것이 훨씬 좋습니다.content = File.read(filename)
Jeff Ward
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.