วิธีอ่านบรรทัดไฟล์ใน Ruby


238

ฉันพยายามใช้รหัสต่อไปนี้เพื่ออ่านบรรทัดจากไฟล์ แต่เมื่ออ่านไฟล์เนื้อหาทั้งหมดจะอยู่ในบรรทัดเดียว:

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

แต่ไฟล์นี้พิมพ์แต่ละบรรทัดแยกกัน


ฉันต้องใช้ stdin เช่นruby my_prog.rb < file.txtที่ฉันไม่สามารถสรุปได้ว่าตัวละครบรรทัดสิ้นสุดคือไฟล์ที่ใช้ ฉันจะจัดการกับมันได้อย่างไร


7
แทนที่จะทำเช่นline_num = 0นั้นคุณสามารถใช้each.each_with_indexหรือเป็นไปeach.with_indexได้
Andrew Grimm

@ andrew-grimm ขอบคุณมันทำให้รหัสสะอาดขึ้น
วาด

ดูstackoverflow.com/q/25189262/128421ทำไมบรรทัดโดยบรรทัด IO readเป็นที่ต้องการมากกว่าการใช้
ชายดีบุก

ใช้line.chompเพื่อจัดการกับจุดสิ้นสุดบรรทัด (ความอนุเคราะห์ของ@SreenivasanAC )
Yarin

คำตอบ:


150

ฉันเชื่อว่าคำตอบของฉันครอบคลุมข้อกังวลใหม่ของคุณเกี่ยวกับการจัดการกับการจบบรรทัดใด ๆ ตั้งแต่ทั้งคู่"\r\n"และ"\r"ถูกแปลงเป็นมาตรฐาน Linux "\n"ก่อนที่จะแยกวิเคราะห์บรรทัด

เพื่อสนับสนุน"\r"ตัวละคร EOL พร้อมกับเรื่องปกติ"\n"และ"\r\n"จาก Windows นี่คือสิ่งที่ฉันจะทำ:

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

แน่นอนว่านี่อาจเป็นความคิดที่ไม่ดีสำหรับไฟล์ที่มีขนาดใหญ่มากเพราะมันหมายถึงการโหลดไฟล์ทั้งหมดลงในหน่วยความจำ


regex นั้นใช้ไม่ได้สำหรับฉัน รูปแบบ Unix ใช้ \ n, windows \ r \ n, mac ใช้ \ n - .gsub (/ (\ r | \ n) + /, "\ n") ทำงานให้ฉันด้วยทุกกรณี
Pod

4
regex ที่ถูกต้องควร/\r?\n/จะครอบคลุมทั้ง \ r \ n และ \ n โดยไม่รวมบรรทัดว่างไว้ตามความคิดเห็นของ Pod
Irongaze.com

12
นี้จะอ่านไฟล์ทั้งหมดในหน่วยความจำซึ่งอาจเป็นไปไม่ได้ขึ้นอยู่กับขนาดไฟล์
eremzeit

1
วิธีนี้ไม่มีประสิทธิภาพสูงมากคำตอบที่นี่คือstackoverflow.com/a/17415655/228589 ซึ่งเป็นคำตอบที่ดีที่สุด โปรดตรวจสอบการใช้งานทั้งสองวิธี
CantGetANick

1
นี่ไม่ใช่วิธีทับทิม คำตอบด้านล่างแสดงพฤติกรรมที่เหมาะสม
Merovex

525

Ruby มีวิธีการนี้:

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

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


methond นี้ช้ากว่า methond นั่นคือ @Olivier L.
HelloWorld

1
@HelloWorld อาจเป็นเพราะการลบแต่ละบรรทัดก่อนหน้าจากหน่วยความจำและโหลดในแต่ละบรรทัดลงในหน่วยความจำ อาจผิด แต่รูบี้อาจทำสิ่งต่าง ๆ ได้อย่างถูกต้อง (เพื่อให้ไฟล์ขนาดใหญ่ไม่ทำให้สคริปต์ของคุณเสีย)
Starkers

คุณสามารถใช้with_indexกับสิ่งนี้ได้เช่นกัน?
Joshua Pinter

1
ใช่คุณสามารถทำได้เช่นFile.readlines(filename).each_with_index { |line, i| puts "#{i}: #{line}" }
wulftone

วิธีนี้ดูดีขึ้น ฉันกำลังอ่านไฟล์ที่มีขนาดใหญ่มากและวิธีนี้จะไม่ทำให้แอปพลิเคชันเสียหายโดยพยายามโหลดไฟล์ทั้งหมดลงในหน่วยความจำพร้อมกัน
Shelby S

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

นี้จะดำเนินการบล็อกที่กำหนดสำหรับแต่ละบรรทัดในไฟล์โดยไม่ต้อง slurping ไฟล์ทั้งหมดลงในหน่วยความจำ ดู: IO :: foreach


10
นี่คือคำตอบ - สำนวน Ruby และไม่เขียนไฟล์ โปรดดูstackoverflow.com/a/5546681/165673
Yarin

4
ทุกคนยกย่องเทพทับทิม!
Joshua Pinter

วิธีการไปยังบรรทัดที่สองภายในวง?
user1735921

18

ไฟล์แรกของคุณมีการสิ้นสุดบรรทัด Mac Classic (นั่นคือ"\r"แทนที่จะเป็นแบบปกติ"\n") เปิดด้วย

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

เพื่อระบุจุดสิ้นสุดบรรทัด


1
น่าเศร้าที่ไม่มีอะไรที่เหมือนกับบรรทัดใหม่สากลใน Python อย่างน้อยที่สุดฉันก็รู้
Josh Lee

อีกหนึ่งคำถามฉันต้องใช้ stdin เช่น ruby ​​my_prog.rb <file.txt ซึ่งฉันไม่สามารถสรุปได้ว่าไฟล์ที่ลงท้ายด้วย char ใช้ไฟล์อะไร ... ฉันจะจัดการได้อย่างไร
วาด

ดูเหมือนว่าคำตอบของ Olivier จะเป็นประโยชน์หากคุณตกลงกับการโหลดไฟล์ทั้งหมดลงในหน่วยความจำ การตรวจจับบรรทัดใหม่ในขณะที่ยังคงสแกนไฟล์จะทำงานได้อีกเล็กน้อย
Josh Lee

7

มันเป็นเพราะการสิ้นสุดในแต่ละบรรทัด ใช้เมธอด chomp ใน ruby ​​เพื่อลบ endline '\ n' หรือ 'r' ที่ท้าย

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

2
@SreenivisanAC +1 สำหรับ chomp!
Yarin

7

ฉันเป็นส่วนหนึ่งของวิธีการต่อไปนี้สำหรับไฟล์ที่มีส่วนหัว:

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

สิ่งนี้อนุญาตให้คุณประมวลผลบรรทัดส่วนหัว (หรือบรรทัด) แตกต่างจากบรรทัดเนื้อหา



4

อย่าลืมว่าถ้าคุณมีความกังวลเกี่ยวกับการอ่านไฟล์ที่อาจมีเส้นขนาดใหญ่ที่อาจทำให้แรมของคุณล้นระหว่างรันไทม์คุณสามารถอ่านไฟล์ทุกมื้อได้ ดูที่ " ทำไมไฟล์ slurping ไม่ดี "

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.