Cara membaca baris file di Ruby


238

Saya mencoba menggunakan kode berikut untuk membaca baris dari file. Tetapi ketika membaca file , isinya semua dalam satu baris:

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

Tetapi file ini mencetak setiap baris secara terpisah.


Saya harus menggunakan stdin, seperti ruby my_prog.rb < file.txt, di mana saya tidak bisa berasumsi apa karakter akhir baris yang digunakan file. Bagaimana saya bisa mengatasinya?


7
Daripada melakukannya line_num = 0, Anda bisa menggunakan each.each_with_indexatau mungkin each.with_index.
Andrew Grimm

@ andrew-grimm terima kasih, ini membuat kode lebih bersih.
gambar

Lihat stackoverflow.com/q/25189262/128421 untuk alasan mengapa IO baris demi baris lebih disukai daripada menggunakan read.
the Tin Man

Gunakan line.chompuntuk menangani ujung garis (milik @SivivivasanAC )
Yarin

Jawaban:


150

Saya percaya jawaban saya mencakup kekhawatiran baru Anda tentang penanganan semua jenis akhir baris karena keduanya "\r\n"dan "\r"dikonversi ke standar Linux "\n"sebelum menguraikan baris.

Untuk mendukung "\r"karakter EOL bersama dengan reguler "\n", dan "\r\n"dari Windows, inilah yang akan saya lakukan:

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

Tentu saja ini bisa menjadi ide buruk pada file yang sangat besar karena itu berarti memuat seluruh file ke dalam memori.


Regex itu tidak berhasil untukku. Format Unix menggunakan \ n, windows \ r \ n, mac menggunakan \ n - .gsub (/ (\ r | \ n) + /, "\ n") bekerja untuk saya dalam semua kasus.
Pod

4
Regex yang benar adalah /\r?\n/yang akan mencakup \ r \ n dan \ n tanpa menggabungkan baris kosong seperti komentar Pod
Irongaze.com

12
Ini akan membaca seluruh file ke dalam memori, yang bisa mustahil tergantung pada seberapa besar file tersebut.
eremzeit

1
Metode ini sangat sangat tidak efisien, jawaban talabes di sini stackoverflow.com/a/17415655/228589 adalah jawaban terbaik. Harap verifikasi implementasi kedua metode ini.
CantGetANick

1
Ini bukan jalan ruby. Jawaban di bawah ini menunjukkan perilaku yang benar.
Merovex

525

Ruby memang memiliki metode untuk ini:

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

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


methond ini lebih lambat daripada methond yaitu @Olivier L.
HelloWorld

1
@ HaloWorld Mungkin karena menghapus setiap baris sebelumnya dari memori dan memuat di setiap baris ke dalam memori. Mungkin salah, tetapi Ruby mungkin melakukan hal-hal dengan benar (sehingga file besar tidak menyebabkan skrip Anda mogok).
Starkers

Bisakah Anda menggunakan with_indexini juga?
Joshua Pinter

1
Ya, Anda bisa, misalnyaFile.readlines(filename).each_with_index { |line, i| puts "#{i}: #{line}" }
wulftone

Metode ini sepertinya lebih baik. Saya membaca file yang sangat besar dan dengan cara ini tidak merusak aplikasi dengan mencoba memuat seluruh file ke memori sekaligus.
Shelby S

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

Ini akan mengeksekusi blok yang diberikan untuk setiap baris dalam file tanpa menghirup seluruh file ke dalam memori. Lihat: IO :: foreach .


10
Ini adalah jawabannya - Ruby idiomatik dan tidak menyeruput file tersebut. Lihat juga stackoverflow.com/a/5546681/165673
Yarin

4
Semua memuji dewa Ruby!
Joshua Pinter

bagaimana cara menuju ke baris kedua di dalam loop?
user1735921

18

File pertama Anda memiliki akhiran garis Mac Classic (itu "\r"bukan yang biasa "\n"). Buka dengan

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

untuk menentukan akhir baris.


1
Sayangnya, tidak ada yang seperti baris baru universal di Python, setidaknya yang saya tahu.
Josh Lee

satu pertanyaan lagi, saya harus menggunakan stdin, seperti ruby ​​my_prog.rb <file.txt, di mana saya tidak dapat mengasumsikan apa yang digunakan oleh baris yang mengakhiri file menggunakan ... Bagaimana saya bisa mengatasinya?
gambar

Jawaban Olivier tampaknya membantu, jika Anda setuju dengan memuat seluruh file ke dalam memori. Mendeteksi baris baru saat masih memindai file akan membutuhkan lebih banyak pekerjaan.
Josh Lee

7

Itu karena endline di setiap baris. Gunakan metode chomp di ruby ​​untuk menghapus garis akhir '\ n' atau 'r' di akhir.

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

2
@SreenivisanAC +1 untuk chomp!
Yarin

7

Saya sebagian dengan pendekatan berikut untuk file yang memiliki header:

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

Ini memungkinkan Anda memproses baris tajuk (atau garis) secara berbeda dari garis konten.


6

bagaimana mendapat ?

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

4

Jangan lupa bahwa jika Anda khawatir tentang membaca dalam file yang mungkin memiliki garis besar yang bisa membanjiri RAM Anda saat runtime, Anda selalu dapat membaca file sepotong-makan. Lihat " Mengapa menghirup file itu buruk ".

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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.