Stellen Sie einer vorhandenen Datei in Python eine Zeile voran

73

Ich muss der ersten Zeile einer Textdatei eine einzelne Zeile hinzufügen, und es sieht so aus, als ob mir nur mehr Codezeilen zur Verfügung stehen, als ich von Python erwarten würde. Etwas wie das:

f = open('filename','r')
temp = f.read()
f.close()

f = open('filename', 'w')
f.write("#testfirstline")

f.write(temp)
f.close()

Gibt es keinen einfacheren Weg? Außerdem sehe ich dieses Beispiel mit zwei Handles häufiger als das Öffnen eines einzelnen Handles zum Lesen und Schreiben ('r +') - warum ist das so?

Nick
quelle
1
(Bemerkenswert: Sie sind wahrscheinlich besser dran, die Datei Zeile für Zeile zu lesen und in eine temporäre Datei zu schreiben. Wenn Sie fertig sind, entfernen Sie die Originaldatei und ersetzen Sie sie durch die temporäre.)
cwallenpoole

Antworten:

93

Python macht viele Dinge einfach und enthält Bibliotheken und Wrapper für viele gängige Operationen, aber das Ziel ist nicht, grundlegende Wahrheiten zu verbergen.

Die grundlegende Wahrheit, auf die Sie hier stoßen, ist, dass Sie einer vorhandenen flachen Struktur im Allgemeinen keine Daten voranstellen können, ohne die gesamte Struktur neu zu schreiben. Dies gilt unabhängig von der Sprache.

Es gibt Möglichkeiten, ein Dateihandle zu speichern oder Ihren Code weniger lesbar zu machen. Viele davon sind in anderen Antworten enthalten, aber nichts ändert die grundlegende Operation: Sie müssen die vorhandene Datei einlesen und dann die Daten ausschreiben, die Sie voranstellen möchten, gefolgt von die vorhandenen Daten, die Sie einlesen.

Sparen Sie sich auf jeden Fall das Dateihandle, aber versuchen Sie nicht, diesen Vorgang in so wenige Codezeilen wie möglich zu packen. Suchen Sie niemals nach den wenigsten Codezeilen - das ist Verschleierung, nicht Programmierung.

Nicholas Knight
quelle
32
"Suchen Sie niemals nach den wenigsten Codezeilen - das ist Verschleierung, nicht Programmierung" - Das Verstecken der Zeit, die für die Ausführung einer Funktion benötigt wird, ist keine Verschleierung, sondern eine Abstraktion. Wenn der Zweck des Codes darin bestehen würde, eine proportionale Zeit zum Lesen und Ausführen zu benötigen, hätte der Code eine völlig andere Struktur als er tatsächlich hat.
Aviendha
"Sie müssen die vorhandene Datei einlesen und dann die Daten ausschreiben, die Sie voranstellen möchten, gefolgt von den vorhandenen Daten, die Sie einlesen." Schreibvorgänge, damit sich der gesamte Inhalt der Datei niemals gleichzeitig im Speicher befinden muss. Der Umgang mit den Details wäre in der Tat eine ausgezeichnete Bibliothek.
Ken Williams
70

Ich würde mich an getrennte Lese- und Schreibvorgänge halten, aber wir können sie sicherlich präziser ausdrücken:

Python2:

with file('filename', 'r') as original: data = original.read()
with file('filename', 'w') as modified: modified.write("new first line\n" + data)

Python3:

with open('filename', 'r') as original: data = original.read()
with open('filename', 'w') as modified: modified.write("new first line\n" + data)

Hinweis: Die Funktion file () ist in Python3 nicht verfügbar.

Karl Knechtel
quelle
1
Bitte beachten Sie, dass die file()-Funktion nicht in Python 3 verfügbar ist, sondern nur in Version 2. Ersetzen Sie sie einfach durch open()Python 3.
Mozzbozz
7
Eigentlich sollten Sie die Dateifunktion auch in Python 2 nicht verwenden. Sie sollten Dateien immer mit der open()Funktion in Python öffnen . Die Dateifunktion ist nur aus historischen Gründen vorhanden.
Henry Schreiner
@HenrySchreiner zu der Zeit fand ich das fileintuitiver, unabhängig von Community-Konsens und gemeinsamen Stilrichtlinien. Aber als 3.x kam (und ich war ein ziemlich eifriger FWIW-Anwender), hatte ich keine Wahl mehr :)
Karl Knechtel
23

Anderer Ansatz:

with open("infile") as f1:
    with open("outfile", "w") as f2:
        f2.write("#test firstline")
        for line in f1:
            f2.write(line)

oder ein Einzeiler:

open("outfile", "w").write("#test firstline\n" + open("infile").read())

Vielen Dank für die Gelegenheit, über dieses Problem nachzudenken :)

Prost

Morlock
quelle
9
with open("file", "r+") as f: s = f.read(); f.seek(0); f.write("prepend\n" + s)
barti_ddu
quelle
3

Sie können einen Schreibaufruf damit speichern:

f.write('#testfirstline\n' + temp)

Wenn Sie 'r +' verwenden, müssen Sie die Datei nach dem Lesen und vor dem Schreiben zurückspulen.

Infrarot
quelle
2
+1, obwohl Sie eine ganze Codezeile hätten speichern können, indem Sief.write('#testfirstline\n' + temp)
mtrw
5
Ich würde empfehlen f.writelines(('#testfirstline\n',tmp)). Wenn dann die Temperatur sehr hoch ist, erstellen Sie keine weitere große Zeichenfolge, um dies alles aufzuschreiben. Oder verwenden Sie einfach die zusätzliche Schreibzeile wie im OP ...
Justin Peel
3

Hier ist ein 3-Liner, den ich für klar und flexibel halte. Es verwendet die Funktion list.insert. Wenn Sie der Datei also wirklich voranstellen möchten, verwenden Sie l.insert (0, 'insert_str'). Als ich dies tatsächlich für ein Python-Modul tat, das ich entwickle, habe ich l.insert (1, 'insert_str') verwendet, weil ich die Zeichenfolge '# - - encoding: utf-8 - -' in Zeile 0 überspringen wollte der Code.

f = open(file_path, 'r'); s = f.read(); f.close()
l = s.splitlines(); l.insert(0, 'insert_str'); s = '\n'.join(l)
f = open(file_path, 'w'); f.write(s); f.close()
Liebe und Frieden - Joe Codeswell
quelle
Sie könnten es auch in einen 1-Liner machen
Shadi
Dieser druckt chinesische Schriftzeichen aus!
Ulf Gjerdingen
2
Hallo Ulf Gjerdingen! Enthält die Datei chinesische Zeichen?
Liebe und Frieden - Joe Codeswell
2

Dies erledigt den Job, ohne die gesamte Datei in den Speicher einzulesen, obwohl dies unter Windows möglicherweise nicht funktioniert

def prepend_line(path, line):
    with open(path, 'r') as old:
        os.unlink(path)
        with open(path, 'w') as new:
            new.write(str(line) + "\n")
            shutil.copyfileobj(old, new)
EU G
quelle
Ich mag das, obwohl Sie vorsichtig sein müssen, da es zu Datenverlust führt, wenn es unterbrochen wird.
Sonntag,
Dadurch wird die Datei überschrieben. Ist es möglich, eine neue Datei zu erstellen, shutil.copyfileobjanstatt sie zu überschreiben?
Alvas
1
Sorry @alvas Ich verstehe nicht ganz was du meinst. Wenn Sie in eine neue Datei schreiben möchten, geben Sie pathbeim zweiten Aufruf einfach eine andere ein open.
Eug
0

Eine Möglichkeit ist die folgende:

import os
open('tempfile', 'w').write('#testfirstline\n' + open('filename', 'r').read())
os.rename('tempfile', 'filename')
JooMing
quelle
2
Dies ist unter POSIX unsicher (Rennbedingungen auf einigen Dateisystemen, XFS, glaube ich). Vor dem Umbenennen müssen f.flush () und os.fsync (f.fileno ()) für die temporäre Datei aufgerufen werden.
Rosh Oxymoron
0

Wenn Sie der Datei nach einem bestimmten Text ein Präfix voranstellen möchten, können Sie die folgende Funktion verwenden.

def prepend_text(file, text, after=None):
    ''' Prepend file with given raw text '''
    f_read = open(file, 'r')
    buff = f_read.read()
    f_read.close()
    f_write = open(file, 'w')
    inject_pos = 0
    if after:
        pattern = after
        inject_pos = buff.find(pattern)+len(pattern)
    f_write.write(buff[:inject_pos] + text + buff[inject_pos:])
    f_write.close()

Zuerst öffnen Sie die Datei, lesen sie und speichern sie in einer Zeichenfolge. Dann versuchen wir, die Zeichennummer in der Zeichenfolge zu finden, in die die Injektion erfolgen soll. Dann können wir mit einem einzigen Schreibvorgang und einer intelligenten Indizierung der Zeichenfolge die gesamte Datei einschließlich des eingefügten Textes neu schreiben.

Pithikos
quelle
0

Sehe ich etwas nicht oder könnten wir nicht einfach einen Puffer verwenden, der groß genug ist, um die Eingabedatei in Teilen (anstelle des gesamten Inhalts) einzulesen, und mit diesem Puffer die Datei durchlaufen, während sie geöffnet ist, und die Datei weiter austauschen <- > Pufferinhalt?

Dies scheint viel effizienter zu sein (insbesondere für große Dateien), als den gesamten Inhalt im Speicher zu lesen , ihn im Speicher zu ändern und ihn in dieselbe oder (noch schlimmer) in eine andere Datei zurückzuschreiben. Es tut mir leid, dass ich jetzt keine Zeit habe, ein Beispiel-Snippet zu implementieren. Ich werde später darauf zurückkommen, aber vielleicht haben Sie die Idee.

Zuzu Corneliu
quelle