2016-03-30 15 views
1

ich eine Textdatei auf Datei, die mit Beginn des Einsatzes:ersten beiden Zeilen löschen und zwei Zeilen hinzufügen,

Title 

aaa 
bbb 
ccc 

Ich weiß nicht, was wäre die Linie gehören, aber ich weiß, dass die Struktur der Datei sei Title, dann eine leere Zeile, dann die tatsächlichen Zeilen. Ich will es ändern zu:

New Title 

fff 
aaa 
bbb 
ccc 

Ich hatte this im Sinn:

lineArray = File.readlines(destinationFile).drop(2) 
lineArray.insert(0, 'fff\n') 
lineArray.insert(0, '\n') 
lineArray.insert(0, 'new Title\n') 
File.writelines(destinationFile, lineArray) 

aber writelines nicht existiert.

`writelines' for File:Class (NoMethodError) 

Gibt es eine Möglichkeit, die ersten beiden Zeilen der Datei zu löschen und drei neue Zeilen hinzuzufügen?

+0

Sie für die Facets Juwel in der Dokumentation verknüpft. Wenn Sie 'File.writelines' verwenden wollen, müssen Sie dieses Juwel installieren. –

+0

@Jordan Gibt es einen eingebauten Weg, dies in Ruby ohne einen Edelstein Dritter zu tun? –

+0

P.S. Der Titel Ihrer Frage sagt "erste zwei Zeilen", aber es sieht so aus, als ob Sie die ersten drei Zeilen ersetzen möchten (eine leere Zeile ist immer noch eine Zeile). FWIW, ein einfacherer Weg, die ersten drei Elemente in einem Array zu ersetzen, ist 'lineArr [0..2] = [" New Title \ n "," \ n "," fff \ n "]' –

Antwort

1

ich mit so etwas wie diese beginnen würde:

NEWLINES = { 
    0 => "New Title", 
    1 => "\nfff" 
} 

File.open('test.txt.new', 'w') do |fo| 
    File.foreach('test.txt').with_index do |li, ln| 
    fo.puts (NEWLINES[ln] || li) 
    end 
end 

Hier ist der Inhalt von test.txt.new nach dem Laufen:

New Title 

fff 
aaa 
bbb 
ccc 

Die Idee ist es, eine Liste von Ersatzlinien im NEWLINES Hash zur Verfügung zu stellen. Da jede Zeile aus der Originaldatei gelesen wird, wird die Zeilennummer im Hash überprüft, und wenn die Zeile existiert, wird der entsprechende Wert verwendet, andernfalls wird die ursprüngliche Zeile verwendet.

Wenn Sie die gesamte Datei dann ersetzen lesen möchten, reduziert es den Code ein wenig, aber der Code wird Skalierbarkeit Probleme haben:

NEWLINES = [ 
    "New Title", 
    "", 
    "fff" 
] 

file = File.readlines('test.txt') 
File.open('test.txt.new', 'w') do |fo| 
    fo.puts NEWLINES 
    fo.puts file[(NEWLINES.size - 1) .. -1] 
end 

Es ist nicht sehr klug, aber es wird für einfachen Ersatz zu arbeiten.

Wenn Sie es wirklich richtig machen wollen, lernen Sie, wie diff funktioniert, erstellen Sie eine Diff-Datei, dann lassen Sie das schwere Heben, wie es für diese Art von Aufgabe konzipiert ist, läuft extrem schnell und wird millionenfach verwendet Jeden Tag auf * nix Systemen auf der ganzen Welt.

+0

Guter Punkt über 'diff'. Vielleicht möchten Sie zeigen, wie das in Ruby gemacht werden könnte. –

+0

Ich dachte daran, aber es ist eine ganz andere Frage. –

1

Verwendung mit der ganzen Reihe setzen:

File.open("destinationFile", "w+") do |f| 
    f.puts(lineArray) 
end 
+0

wird dies Zeile für Zeile in die Datei schreiben? Wenn ja, wäre das nicht die schlechte Praxis für große Dateien? –

+0

Dies sollte schnell genug sein, da es keine Möglichkeit gibt, Array in Datei zu schreiben, ohne über das Array zu gehen ... –

+0

Ich glaube, das OP möchte eine Möglichkeit, die ersten 2 Zeilen der Datei zu löschen und dann 3 neue Zeilen einzufügen der Anfang ** ohne ** die ganze Datei einzulesen und dann die ganze Datei zu schreiben, was ich mit den 'File' Methoden von Ruby unmöglich finde. –

1

Wenn Ihre Dateien groß sind, lohnt es sich, über die Leistung und den Speicher nachzudenken, wenn Sie sie vollständig in den Speicher einlesen. Wenn das ein Problem ist, ist es am besten, die Dateien als Streams zu behandeln. So würde ich es machen.

Zunächst definieren Ersatztext:

require "stringio" 

replacement = StringOI.new <<END 
New Title 

fff 
END 

ich dies ein StringIO Objekt gemacht habe, aber es könnte auch ein File-Objekt, wenn Ihr Ersatztext in einer Datei sein.

Öffnen Sie nun Ihre Zieldatei (eine neue Datei) und schreiben Sie jede Zeile aus dem Ersetzungstext hinein.

dest = File.open(dest_fn, 'wb') do |dest| 
replacement.each_line {|ln| dest << ln } 

Ich dies könnte effizienter gemacht, aber es gibt einen guten Grund, es auf diese Weise zu tun: Jetzt können wir replacement.lineno nennen die Anzahl der Zeilen ein zweites Mal von Iterieren lesen zu bekommen, statt über sie die zählen Linien.

Als nächstes öffnen Sie die Originaldatei und suchen vor durch getsreplacement.lineno mal anrufen:

orig = File.open(orig_fn, 'r') 
replacement.lineno.times { orig.gets } 

schließlich die restlichen Zeilen aus der ursprünglichen Datei in die neue Datei schreiben. Wir werden es tun effizienter dieser Zeit mit File.copy_stream:

File.copy_stream(orig, dest) 
orig.close 
dest.close 

Das ist es. Natürlich ist es ein Ziehen, diese Dateien manuell zu schließen (und wenn wir es tun, sollten wir es in einem ensure Block machen), also ist es besser, die Blockform von File.open zu verwenden, um sie automatisch zu schließen. Außerdem können wir die orig.gets Anrufe in die replacement.each_line Schleife bewegen:

File.open(dest_fn, 'wb') do |dest| 
    File.open(orig_fn, 'r') do |orig| 
    replacement.each_line {|ln| dest << ln; orig.gets } 
    File.copy_stream(orig, dest) 
    end 
end 
0

zunächst eine Eingangstestdatei erstellen.

FNameIn = "test_in" 

text = <<_ 
Title 

How now, 
brown cow? 
_ 
    #=> "Title\n\nHow now,\nbrown cow?\n" 

File.write(FNameIn, text) 
    #=> 27 

Jetzt lesen und schreiben Zeile für Zeile.

FNameOut = "test_out" 

File.open(FNameIn) do |fin| 
    fin.gets; fin.gets 
    File.open(FNameOut, 'w') do |fout| 
    fout.puts "New Title" 
    fout.puts 
    fout.puts "fff" 
    until fin.eof?  
     fout.puts fin.gets 
    end 
    end 
end 

Überprüfen Sie das Ergebnis:

puts File.read(FNameOut) 
    # New Title 
    # 
    # fff 
    # How now, 
    # brown cow? 

Ruby jeder der beiden Dateien schließen, wenn seine Block beendet.

Wenn die Dateien nicht groß sind, könnten Sie stattdessen schreiben:

File.write(FNameOut, 
    ["New Title\n", "\n", "fff\n"].concat(File.readlines(FNameIn).drop(2)).join) 
Verwandte Themen