रूबी में फ़ाइल पढ़ने के सभी सामान्य तरीके क्या हैं?


280

रूबी में फ़ाइल पढ़ने के सभी सामान्य तरीके क्या हैं?

उदाहरण के लिए, यहाँ एक विधि है:

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

मुझे पता है कि रूबी बेहद लचीली है। प्रत्येक दृष्टिकोण के लाभ / कमियां क्या हैं?


6
मुझे नहीं लगता कि मौजूदा जीत का जवाब सही है।
13

जवाबों:


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बजाय का उपयोग करें । openeach_line
टिन मैन

7
f.each { |line| ... }और f.each_line { |line| ... }ऐसा ही व्यवहार लगता है (कम से कम रूबी 2.0.0 में)।
चब्रॉन

327

यदि फ़ाइल बहुत लंबी नहीं है तो सबसे आसान तरीका है:

puts File.read(file_name)

वास्तव में, IO.readया File.readस्वचालित रूप से फ़ाइल को बंद करें, इसलिए File.openब्लॉक के साथ उपयोग करने की कोई आवश्यकता नहीं है ।


16
IO.readया File.readस्वचालित रूप से फ़ाइल को बंद करें, हालांकि आपका शब्दांकन ऐसा लगता है जैसे वे नहीं करते हैं।
फ्रॉग्ज

15
उन्होंने पहले ही कहा "यदि फ़ाइल बहुत लंबी नहीं है"। मेरे केस को पूरी तरह से सूट करता है।
jayP

227

"सुस्त" फाइलों से सावधान रहें। जब आप एक ही बार में पूरी फ़ाइल को मेमोरी में पढ़ते हैं।

समस्या यह है कि यह अच्छी तरह से पैमाने पर नहीं है। आप एक यथोचित आकार की फ़ाइल के साथ कोड विकसित कर सकते हैं, फिर इसे उत्पादन में डाल सकते हैं और अचानक पा सकते हैं कि आप गीगाबाइट्स में मापने वाली फ़ाइलों को पढ़ने की कोशिश कर रहे हैं, और आपका होस्ट फ्रीज़ हो रहा है क्योंकि यह पढ़ने और स्मृति आवंटित करने का प्रयास करता है।

लाइन-बाय-लाइन I / O बहुत तेज़ है, और लगभग हमेशा स्लैपिंग जितना प्रभावी होता है। यह वास्तव में आश्चर्यजनक रूप से तेज है।

मुझे उपयोग करना पसंद है:

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

या

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

फ़ाइल IO से विरासत में मिली, और foreachIO में है, इसलिए आप या तो उपयोग कर सकते हैं।

मैं कुछ के माध्यम से बड़ी फ़ाइलों को पढ़ने की कोशिश कर के प्रभाव दिखा बेंचमार्क है readपर "पंक्ति-दर-पंक्ति आई / ओ बनाम क्यों है" slurping "फ़ाइल एक अच्छा अभ्यास नहीं? "।


6
यही वह है जिसकी तलाश में मैं हूं। मुझे पाँच मिलियन लाइनों के साथ एक फ़ाइल मिली है, और वास्तव में वह मेमोरी में लोड नहीं करना चाहता था।
स्कूटी 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

बाइनरी फ़ाइलों के मामले में, आप एक नील-विभाजक और एक ब्लॉक आकार निर्दिष्ट कर सकते हैं, जैसे:

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

संदर्भ: फ़ाइल एपीआई और आईओ एपीआई


2
for_eachफाइल या आईओ में कोई नहीं है। foreachइसके बजाय उपयोग करें ।
द टीन मैन

1
मैं आमतौर पर सबलाइम टेक्स्ट एडिटर का उपयोग रूबीमर्कर्स प्लगइन के साथ करता हूं, जब कोडिंग का दस्तावेजीकरण यहां उत्तरों में किया जाता है। यह आईआरबी का उपयोग करने के समान, मध्यवर्ती परिणाम दिखाना वास्तव में आसान बनाता है। इसके अलावा सब्लिम टेक्स्ट 2 के लिए व्यूइंग इज़ बिल्टिंग प्लगइन वास्तव में शक्तिशाली है।
टिन मैन

1
बहुत बढ़िया जवाब। अंतिम उदाहरण के लिए मैं सुझाव दे सकता हूं कि यह सुनिश्चित करने के लिए कि कोई अपवाद उठाया गया है, भले ही फ़ाइल बंद हो जाए, यह सुनिश्चित करने के लिए और whileइसके बजाय का loopउपयोग ensureकरना। इस तरह (सेमी-कॉलन्स को नई सुर्खियों के साथ बदलें) begin; f = File.open('testfile'); while line = f.gets; puts line; end; ensure; f.close; end:।
एंटीनेम

1
हाँ, जो बहुत बेहतर है @antinome, उत्तर में सुधार हुआ है। धन्यवाद!
विक्टर क्लॉस

26

एक सरल विधि का उपयोग करना है readlines:

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

इनपुट फ़ाइल में प्रत्येक पंक्ति सरणी में एक प्रविष्टि होगी। विधि आपके लिए फ़ाइल खोलने और बंद करने का काम संभालती है।


5
जैसा कि readया किसी भी संस्करण के साथ, यह पूरी फ़ाइल को मेमोरी में खींच लेगा, जो कि बड़ी समस्या हो सकती है यदि फ़ाइल उपलब्ध मेमोरी से बड़ी है। इसके अलावा, क्योंकि यह एक सरणी है, रूबी को सरणी बनाना है, इसके अलावा प्रक्रिया को धीमा करना है।
टिन मैन


9

मैं आमतौर पर ऐसा करता हूं:

open(path_in_string, &:read)

यह आपको पूरे टेक्स्ट को एक स्ट्रिंग ऑब्जेक्ट के रूप में देगा। यह केवल रूबी 1.9 के तहत काम करता है।


यह अच्छा और छोटा है! क्या यह फ़ाइल को भी बंद कर देता है?
मर्गग्रीफुर

5
यह इसे बंद कर देता है, लेकिन यह स्केलेबल नहीं है इसलिए सावधान रहें।
टिन मैन

3

अपने n_file.log या .txt से अंतिम n पंक्तियाँ लौटाएँ

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

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

1

ऑपरेटिंग सिस्टम के कर्नेल को एक फ़ाइल खोलने के लिए कहकर एक और भी अधिक कुशल तरीका स्ट्रीमिंग किया जाता है, फिर इसे बिट से बिट द्वारा पढ़ें। रूबी में प्रति पंक्ति एक फ़ाइल पढ़ते समय, डेटा को एक बार में 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 }

इसके बारे में इस विस्तृत पोस्ट में यहाँ पढ़ें:

रूबी मैजिक स्लपिंग एंड स्ट्रीमिंग फाइल्स बाइ एप्साइनगल


यह देखें: कि कोड अंतिम पंक्ति को अनदेखा करेगा यदि वह लाइनफीड (कम से कम लिनक्स में) के साथ समाप्त नहीं होता है।
जोर्गन

मुझे लगता है कि "@ io.close" से पहले "block.call (@buffer)" डालने से अपूर्ण अधूरी रेखा उठेगी। हालांकि, मैंने रूबी के साथ केवल एक दिन खेला है ताकि मैं गलत हो सकूं। इसने मेरे आवेदन में काम किया :)
जोर्गन

AppSignal पोस्ट को पढ़ने के बाद ऐसा लगता है कि यहाँ एक छोटी सी गलतफहमी हो गई है। कोड जो आपने उस पोस्ट से कॉपी किया था जो बफ़र्ड IO करता है, उदाहरण है कि Ruby वास्तव में File.foreach, या IO.foreach (जो एक ही विधि हैं) के साथ क्या करता है। उनका उपयोग किया जाना चाहिए, और आपको उन्हें इस तरह से फिर से लागू करने की आवश्यकता नहीं है।
पीटर एच। बोलिंग

@ पीटरह.बोलिंग मैं ज्यादातर समय उपयोग-और-न-करने वाली मानसिकता को पुन: लागू करने के लिए कर रहा हूं। लेकिन माणिक हमें चीजों को खोलने की अनुमति देता है और शर्म की बात है कि यह एक भत्तों में से एक है। विशेष रूप से माणिक / रेल में कोई वास्तविक 'होना चाहिए' या नहीं होना चाहिए। जब तक आप जानते हैं कि आप क्या कर रहे हैं, और आप इसके लिए परीक्षण लिखते हैं।
खलील घरौई

0
content = `cat file`

मुझे लगता है कि यह विधि सबसे "असामान्य" है। शायद यह एक तरह से मुश्किल है, लेकिन अगर catयह स्थापित है तो यह काम करता है।


1
एक आसान ट्रिक, लेकिन शेल को कॉल करने पर बहुत सारे नुकसान होते हैं, जिनमें 1) कमांड अलग-अलग OS पर भिन्न हो सकते हैं, 2) आपको फ़ाइल नाम में रिक्त स्थान से बचने की आवश्यकता हो सकती है। रूबी बिल्ट-इन फ़ंक्शंस का उपयोग करके आप बहुत बेहतर हैं, जैसेcontent = File.read(filename)
जेफ वार्ड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.