Cách đọc các dòng của tệp trong Ruby


237

Tôi đã cố gắng sử dụng đoạn mã sau để đọc các dòng từ một tập tin. Nhưng khi đọc một tệp , tất cả các nội dung trong một dòng:

line_num=0
File.open('xxx.txt').each do |line|
  print "#{line_num += 1} #{line}"
end

Nhưng tập tin này in riêng từng dòng.


Tôi phải sử dụng stdin, như ruby my_prog.rb < file.txt, nơi tôi không thể giả sử ký tự kết thúc dòng là gì mà tệp sử dụng. Làm thế nào tôi có thể xử lý nó?


7
Thay vì làm line_num = 0, bạn có thể sử dụng each.each_with_indexhoặc có thể each.with_index.
Andrew Grimm

@ andrew-grimm cảm ơn bạn, nó làm cho mã sạch hơn.
vẽ

Xem stackoverflow.com/q/25189262/128421 để biết lý do tại sao IO từng dòng được ưa thích hơn sử dụng read.
Tin Man

Sử dụng line.chompđể xử lý các kết thúc dòng (lịch sự của @SreenivasanAC )
Yarin

Câu trả lời:


150

Tôi tin rằng câu trả lời của tôi bao gồm các mối quan tâm mới của bạn về việc xử lý bất kỳ loại kết thúc dòng nào vì cả hai "\r\n""\r"được chuyển đổi sang tiêu chuẩn Linux "\n"trước khi phân tích các dòng.

Để hỗ trợ "\r"nhân vật EOL cùng với thông thường "\n""\r\n"từ Windows, đây là những gì tôi sẽ làm:

line_num=0
text=File.open('xxx.txt').read
text.gsub!(/\r\n?/, "\n")
text.each_line do |line|
  print "#{line_num += 1} #{line}"
end

Tất nhiên đây có thể là một ý tưởng tồi trên các tệp rất lớn vì nó có nghĩa là tải toàn bộ tệp vào bộ nhớ.


Regex đó đã không làm việc cho tôi. Định dạng Unix sử dụng \ n, windows \ r \ n, mac sử dụng \ n - .gsub (/ (\ r | \ n) + /, "\ n") hoạt động với tôi trong mọi trường hợp.
Pod

4
Regex đúng phải là /\r?\n/bao gồm cả \ r \ n và \ n mà không kết hợp các dòng trống như nhận xét của Pod sẽ làm
Irongaze.com

12
Điều này sẽ đọc toàn bộ tệp vào bộ nhớ, điều này có thể là không thể tùy thuộc vào độ lớn của tệp.
eremzeit

1
Phương pháp này rất không hiệu quả, Talabes trả lời ở đây stackoverflow.com/a/17415655/228589 là câu trả lời tốt nhất. Vui lòng xác minh việc thực hiện hai phương pháp này.
CantGetANick

1
Đây không phải là cách ruby. Câu trả lời dưới đây cho thấy hành vi đúng.
Merovex

524

Ruby có một phương pháp cho việc này:

File.readlines('foo').each do |line|

http://ruby-doc.org/core-1.9.3/IO.html#method-c-readlines


methond này chậm hơn methond đó là @Olivier L.
HelloWorld

1
@HelloWorld Có lẽ vì nó xóa từng dòng trước khỏi bộ nhớ và tải từng dòng vào bộ nhớ. Có thể sai, nhưng Ruby có thể làm mọi thứ đúng cách (để các tệp lớn không khiến tập lệnh của bạn bị sập).
Starkers

Bạn có thể sử dụng with_indexvới điều này là tốt?
Joshua Pinter

1
Vâng, bạn có thể, ví dụFile.readlines(filename).each_with_index { |line, i| puts "#{i}: #{line}" }
wulftone

Phương pháp này có vẻ tốt hơn. Tôi đang đọc các tệp rất lớn và bằng cách này, nó không làm hỏng ứng dụng bằng cách tải toàn bộ tệp vào bộ nhớ cùng một lúc.
Shelby S

392
File.foreach(filename).with_index do |line, line_num|
   puts "#{line_num}: #{line}"
end

Điều này sẽ thực thi khối đã cho cho mỗi dòng trong tệp mà không đưa toàn bộ tệp vào bộ nhớ. Xem: IO :: foreach .


10
Đây là câu trả lời - Ruby thành ngữ và không làm lu mờ tập tin. Xem thêm stackoverflow.com/a/5546681/165673
Yarin

4
Tất cả đều ca ngợi các vị thần Ruby!
Joshua Pinter

Làm thế nào để đi đến dòng thứ hai trong vòng lặp?
dùng1735921

18

Tệp đầu tiên của bạn có kết thúc dòng Mac Classic ( "\r"thay vì thông thường "\n"). Mở nó với

File.open('foo').each(sep="\r") do |line|

để chỉ định các kết thúc dòng.


1
Đáng buồn thay, không có gì giống như các dòng mới phổ quát trong Python, ít nhất là tôi biết.
Josh Lee

một câu hỏi nữa, tôi phải sử dụng stdin, như ruby ​​my_prog.rb <file.txt, trong đó tôi không thể giả sử dòng kết thúc char mà tệp sử dụng là gì ... Làm cách nào tôi có thể xử lý nó?
vẽ

Câu trả lời của Olivier có vẻ hữu ích, nếu bạn ổn với việc tải toàn bộ tệp vào bộ nhớ. Phát hiện dòng mới trong khi vẫn quét tệp sẽ mất nhiều công sức hơn.
Josh Lee

7

Đó là bởi vì các dòng cuối trong mỗi dòng. Sử dụng phương pháp chomp trong ruby ​​để xóa dòng cuối '\ n' hoặc 'r' ở cuối.

line_num=0
File.open('xxx.txt').each do |line|
  print "#{line_num += 1} #{line.chomp}"
end

2
@SreenivisanAC +1 cho chomp!
Yarin

7

Tôi là một phần của cách tiếp cận sau đây đối với các tệp có tiêu đề:

File.open(file, "r") do |fh|
    header = fh.readline
    # Process the header
    while(line = fh.gets) != nil
        #do stuff
    end
end

Điều này cho phép bạn xử lý một dòng tiêu đề (hoặc dòng) khác với các dòng nội dung.


6

làm thế nào được ?

myFile=File.open("paths_to_file","r")
while(line=myFile.gets)
 //do stuff with line
end

4

Đừng quên rằng nếu bạn lo lắng về việc đọc trong một tệp có thể có các dòng lớn có thể chiếm dụng RAM của bạn trong thời gian chạy, bạn luôn có thể đọc phần ăn của tệp. Xem " Tại sao làm mờ một tập tin là xấu ".

File.open('file_path', 'rb') do |io|
  while chunk = io.read(16 * 1024) do
    something_with_the chunk
    # like stream it across a network
    # or write it to another file:
    # other_io.write chunk
  end
end
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.