2011-12-24 13 views
12

साथ फाइल करने के लिए मैं इस तरह रूबी के साथ फ़ाइल के शीर्ष एक करने के लिए एक पंक्ति जोड़ना चाहते हैं एक पंक्ति:प्रारंभ में लगा रूबी

# initial file contents 
something 
else 

# file contents after prepending "hello" on its own line 
hello 
something 
else 

निम्नलिखित कोड सिर्फ पूरी फ़ाइल की सामग्री को बदल:

f = File.new('myfile', 'w') 
f.write "test string" 

उत्तर

19

यह एक बहुत आम कार्य है:

#!usr/bin/ruby 

f = File.open("myfile", "r+") 
lines = f.readlines 
f.close 

lines = ["something\n"] + lines 

output = File.new("myfile", "w") 
lines.each { |line| output.write line } 
output.close 
2

ऐसा करने के लिए कोई तंत्र मौजूद नहीं है जो आप आसानी से करना चाहते हैं।

इसके बजाय, आपको फ़ाइल खोलने, फ़ाइल को हटाने, पुराने नाम से एक नई फ़ाइल खोलने, अपनी सामग्री लिखने, और फिर पुरानी फ़ाइल की सामग्री से नई फ़ाइल लिखने की आवश्यकता होगी। यह सुंदर लग घुमावदार लेकिन कोड में सीधा है है:

$ cat prepend.rb 
#!/usr/bin/ruby 

File.open("passwd", "r") do |orig| 
    File.unlink("passwd") 
    File.open("passwd", "w") do |new| 
     new.write "test string" 
     new.write(orig.read()) 
    end 
end 

ध्यान दें कि तंत्र मैं का उपयोग किया है त्रुटियां देखकर परेशान नहीं करता है - आप शायद प्रत्येक File.open() अनुरोध और File.unlink() अनुरोध पर त्रुटियों को संभाल चाहिए - और यह मानता है कि फ़ाइल की पूरी सामग्री स्मृति में फिट होगी। एक छोटी उदाहरण:

$ rm passwd 
$ cp /etc/passwd . 
$ ./prepend.rb 
$ head passwd 
test stringroot:x:0:0:root:/root:/bin/bash 
daemon:x:1:1:daemon:/usr/sbin:/bin/sh 
bin:x:2:2:bin:/bin:/bin/sh 
sys:x:3:3:sys:/dev:/bin/sh 
sync:x:4:65534:sync:/bin:/bin/sync 
games:x:5:60:games:/usr/games:/bin/sh 
man:x:6:12:man:/var/cache/man:/bin/sh 
lp:x:7:7:lp:/var/spool/lpd:/bin/sh 
mail:x:8:8:mail:/var/mail:/bin/sh 
news:x:9:9:news:/var/spool/news:/bin/sh 
$ 

आप फ़ाइलों को स्मृति में पूरी तरह से फिट नहीं हो सकता है हैंडल करना चाहते हैं, तो आप एक तरह से इस तरह एक पाश कोड चाहिए (अपरीक्षित - बेहतर यह छद्म कोड पर विचार करें):

while (data=orig.read(4096)) { 
    new.write(data) 
} 

एक विकल्प के रूप में, आप एक अस्थायी फ़ाइल को लिख सकते हैं, और यदि लेखन प्रक्रिया सफल हो जाती है, तो फ़ाइल को हटाएं और अस्थायी फ़ाइल का नाम बदलें। जो भी दृष्टिकोण आपको सबसे ज्यादा समझ में आता है।

original_file = './original_file' 
new_file = original_file + '.new' 

परीक्षण सेट करें::

File.copy_stream(myfile,tempfile) 
f = File.open(myfile,'w') 
f.write("Hello\n#{File.open(tempfile,'r').read}") 
f.close 
File.delete(tempfile) 
7

fwiw यह काम करने लगता है

File.open(original_file, 'w') do |fo| 
    %w[something else].each { |w| fo.puts w } 
end 

यह वास्तविक कोड है:

File.open(new_file, 'w') do |fo| 
    fo.puts 'hello' 
    File.foreach(original_file) do |li| 
    fo.puts li 
    end 
end 

सुरक्षित कुछ करने के लिए पुराने फ़ाइल का नाम बदलें:

File.rename(original_file, original_file + '.old') 
File.rename(new_file, original_file) 

दिखाओ कि यह काम करता है:

puts `cat #{original_file}` 
puts '---' 
puts `cat #{original_file}.old` 

कौन सा आउटपुट:

hello 
something 
else 
--- 
something 
else 

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

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

+5

फ़ाइल को स्लिपिंग सावधान रहें। यह स्मृति में पूरी फ़ाइल को पढ़ने के लिए एक स्केलेबल समाधान नहीं है। –

+0

मुझे यह व्यक्तिगत रूप से सरल टिंकरिंग के लिए पसंद है। – steve

+0

सरल मामले के लिए सबसे अच्छा समाधान। –

2

आप इस कोशिश कर सकते हैं:

2

मैं कुछ इस तरह के साथ आया है, यह थोड़ा और अधिक वर्णनात्मक और कम अन्य समाधान की तुलना में गुप्त है देखा है मैं:

def file_prepend(file, str) 
    new_contents = "" 
    File.open(file, 'r') do |fd| 
    contents = fd.read 
    new_contents = str << contents 
    end 
    # Overwrite file but now with prepended string on it 
    File.open(file, 'w') do |fd| 
    fd.write(new_contents) 
    end 
end 

और तुम इस तरह इसका इस्तेमाल कर सकते हैं:

file_prepend("target_file.txt", "hello world!\n") 
+0

महान जवाब! इसे एक ऐप में पुन: उपयोग कर सकते हैं। सर्वश्रेष्ठ समाधान आईएमओ। धन्यवाद! – sjsc

2

जैसा कि कुछ ने कहा है, शायद इसे बड़ी फ़ाइलों के लिए उपयोग न करें, लेकिन यह एक साधारण शुरुआत है।

rd = IO.read 'myfile' 
IO.write 'myfile', "hello\n" + rd 
0

कमांड लाइन से, आप कर सकते हैं:

ruby -i -pe '$_= "prepended text\n"+$_ if $. == 1' myfile 

या अधिक कुशलता से

ruby -i -pe 'BEGIN { gets; print "prepended text\n" + $_ }; ' myfile 
दुर्भाग्य

, यह पता चला है, -i (यथा-स्थान) विकल्प नहीं है वास्तव में जगह में, हालांकि (और न ही उस मामले के लिए sed एस इन-प्लेस विकल्प है) - मेरी फ़ाइल में सेशन के बाद एक अलग इनोड होगा।

इससे मुझे दुःख हुआ, क्योंकि प्रभावी रूप से, अगर मैं इसकी दो प्रतियों के लिए पर्याप्त डिस्कस्पेस नहीं रखता, तो मैं एक बड़ी फ़ाइल (प्रीपेड) से फ़िल्टर नहीं कर सकता।

इसे जगह में करना वास्तव में मुश्किल नहीं है, हालांकि (सामान्य रूप से फ़िल्टर करना, न केवल पहली पंक्ति के लिए)। तुम सब करने की ज़रूरत है:

1) यकीन है कि, आप अलग पढ़ लिया है और पढ़ने और लिखने) 2 के लिए संकेत (या अलग फ़ाइल वस्तुओं लिखने बनाना) सुनिश्चित करें कि आप अपठित भागों है कि आप को फिर से लिखने जा रहे हैं बफ़र कर लिया है 3) अगर आपके फ़िल्टरिंग ऑपरेशन को एक छोटी फ़ाइल

के साथ समाप्त होना चाहिए तो मैंने अंत में फाइल करने के लिए छेड़छाड़ की है। मैंने https://github.org/pjump/i_rewriter पर रैपर क्लास लिखा था।

इसके साथ, आप कर सकते हैं

Rewriter.new("myfile") do |line, index| 
    index == 0 ? "prepended text\n" + line : line 
end 

या निष्पादन के साथ: ध्यान से

$ i_rewriter 'index == 0 ? "prepended text\n" + line : line' myfile 

उपयोग करें (यह कर सकते हैं भ्रष्ट आपकी फ़ाइल यदि बाधित)।

0

शुद्ध, लेकिन काम करता है। फ़ाइल से संबंधित संचालन को कम करें।

`#!/bin/ruby 
inv_file = File.open("./1.txt","r+") { |f| 
    #Read file string by-string 
    until f.eof? 
     #Searching for some 
     if f.readline[/condition here/] 
      #remember position 
      offset = f.pos 
      #Find it? - stop reading 
      break 
     end 
    end 
    #Remember what contains rest of file 
    tail = f.readlines 
    #Again to offset 
    f.pos = offset 
    #insert what necessary 
    f.puts "INSERTED" 
    #reconstruct tail 
    f.write tail.join 
    }` 
संबंधित मुद्दे