2009-12-10 3 views
22

Wie kann man die allerletzte Zeile einer Datei mit Python löschen?Löschen Sie die letzte Zeile in der Datei mit Python

Eingabedatei Beispiel:

hello 
world 
foo 
bar 

Ausgabedatei Beispiel:

hello 
world 
foo 

Ich habe den folgenden Code erstellt die Anzahl der Zeilen in der Datei zu finden - aber ich weiß nicht, wie man Löschen Sie die spezifische Zeilennummer. Ich bin neu bei Python - also wenn es einen einfacheren Weg gibt - bitte sag es mir.

try: 
     file = open("file") 
    except IOError: 
     print "Failed to read file." 
    countLines = len(file.readlines()) 

EDIT:

ich es heraus eine Vielzahl von Antworten mit: Meistens Erdbeere und etwas, was ich in der Bahn sah (sorry, ich kann den Link nicht finden).

#!/usr/bin/env python 

import os, sys 

readFile = open("file") 

lines = readFile.readlines() 

readFile.close() 
w = open("file",'w') 

w.writelines([item for item in lines[:-1]]) 

w.close() 
+1

Versuchen Sie, um tatsächlich die Zeile aus der Datei zu entfernen, auf der Festplatte? Wenn ja, stellen Sie sicher, dass Sie verstehen, dass Dateien aus der Sicht des Dateisystems keine "Zeilen" haben. Linien sind eine Konvention von Programmierern und Programmen. Was Sie als "Zeile" sehen, ist eine Folge von Bytes irgendwo in der Mitte von vielen anderen Bytes. Um die letzte "Zeile" zu entfernen, könnten Sie die Datei an dem Byte abschneiden, das dem ersten Zeichen in der Zeile entspricht. Das ist nicht schwierig (Sie müssen es nur finden), aber es ist nicht viel Sinn, wenn die beteiligten Dateien nicht viele Megabyte groß sind. –

+0

Was ist, wenn die letzte Zeile eine leere Zeile ist? – FogleBird

+0

Die letzte Zeile ist nicht leer. Ich entferne alle leeren Zeilen mit einem anderen Python-Snippet (von Google). – torger

Antwort

8

Sie können den obigen Code verwenden und dann: -

lines = file.readlines() 
lines = lines[:-1] 

Dies würde Ihnen eine Reihe von Linien alle Linien enthalten, aber die letzte.

+2

Funktioniert das gut für große Dateien? Z.B. Tausende von Linien? – torger

+0

@Nazarius, es erfordert, dass Sie die gesamte Datei lesen. –

+3

Es funktioniert möglicherweise nicht gut für Dateien größer als ein Megabyte oder zwei. Hängt von Ihrer Definition von "gut" ab. Es sollte für jeden Desktop-Einsatz für ein paar tausend Zeilen vollkommen in Ordnung sein. –

6

Dies verwendet nicht Python, aber Python ist das falsche Werkzeug für den Job, wenn dies die einzige Aufgabe ist, die Sie wollen. Sie können den Standard * nix-Dienstprogramm head verwenden und

head -n-1 filename > newfile 

laufen, die alle bis auf die letzte Zeile des Dateinamens newFile kopiert.

+0

Ich möchte es plattformübergreifend behalten - daher der via python in der Frage. – torger

+4

Dies funktioniert nicht auf Mac OSX: head: illegale Zeilenzählung - -1 –

3

Auf Systemen, wo file.truncate() Arbeiten Sie so etwas tun könnte:

file = open('file.txt', 'rb') 
pos = next = 0 
for line in file: 
    pos = next # position of beginning of this line 
    next += len(line) # compute position of beginning of next line 
file = open('file.txt', 'ab') 
file.truncate(pos) 

Nach meinen Tests file.tell() funktioniert nicht, wenn durch die Linie zu lesen, vermutlich aufgrund verwirrend es Pufferung. Deshalb summiert sich die Länge der Linien, um Positionen zu ermitteln. Beachten Sie, dass dies nur auf Systemen funktioniert, bei denen der Zeilenbegrenzer mit '\ n' endet.

+0

Sehr gefährlich auf einer Plattform, die mehr als ein Zeichen für "Ende der Zeile" verwendet ... wie in Windows. –

+0

Guter Punkt. (Das war eigentlich der Grund, warum ich ursprünglich tell() verwenden wollte, aber es funktioniert nicht.) In diesem Fall sollte die Datei im Binärmodus geöffnet werden. –

+0

Ich würde auch mit Kürzung gehen, vor allem für große Dateien. – alexis

4

Angenommen, Sie haben dies in Python zu tun, und dass Sie eine große genug, dass die Liste Slicing-Datei nicht ausreicht, können Sie es in einem einzigen Durchlauf über die Datei tun:

last_line = None 
for line in file: 
    if last_line: 
     print last_line # or write to a file, call a function, etc. 
    last_line = line 

nicht die eleganter Code in der Welt, aber es macht die Arbeit erledigt.

Grundsätzlich puffert jede Zeile in einer Datei durch die last_line-Variable, jede Iteration gibt die vorherige Iterationszeile aus.

0

Obwohl ich es nicht getestet habe (bitte keinen Hass dafür) Ich glaube, dass es einen schnelleren Weg gibt, es zu gehen. Es ist eher eine C-Lösung, aber in Python durchaus möglich. Es ist auch nicht Pythonic. Es ist eine Theorie, würde ich sagen.

Zuerst müssen Sie die Codierung der Datei kennen. Setzen Sie eine Variable auf die Anzahl der Bytes, die ein Zeichen in dieser Codierung verwendet (1 Byte in ASCII). CHARsize (warum nicht). Wahrscheinlich wird es 1 Byte mit einer ASCII-Datei sein.

Dann greifen Sie die Größe der Datei, setzen FILEsize zu ihm.

Angenommen, Sie haben die Adresse der Datei (im Speicher) in FILEadd.

Hinzufügen FILEsize bis FILEadd.

Verschieben rückwärts gehen (Zuwachs um -1 *** CHARsize **), die Bytes jeden CHARsize Prüfung für ein \ n (oder was auch immer Newline Ihr System verwendet). Wenn Sie das erste \ n erreichen, haben Sie jetzt die Position des Beginns der ersten Zeile der Datei. Ersetzen Sie \ n durch \ x1a (26, das ASCII für EOF, oder was auch immer Ihr System/mit der Kodierung ist).

Aufräumen, aber Sie müssen (ändern Sie die Dateigröße, berühren Sie die Datei).

Wenn dies funktioniert, wie ich es vermutete, werden Sie eine Menge Zeit sparen, da Sie nicht die ganze Datei von Anfang an durchlesen müssen, lesen Sie vom Ende.

+0

Beachten Sie, dass das ganze \ x1a (aka^Z aka CTRL-Z aka EOF, das ist wirklich SUB in ASCII) Sache ist total letzten Jahrhundert ... sehr wenige Textdateien sind mit einem tatsächlichen SUB-Zeichen nicht mehr abgeschlossen, und sogar diese sind auf Windows/DOS-Systeme beschränkt. Und CPM denke ich. –

+0

Ah guter Punkt - Ich war mir nicht sicher, ob es noch weit verbreitet war ... kann etwas anderes verwendet werden, um diese Technik zu retten? – Isaac

0

hier ist eine andere Art und Weise, ohne die gesamte Datei in den Speicher Schlürfen

p="" 
f=open("file") 
for line in f: 
    line=line.strip() 
    print p 
    p=line 
f.close() 
0

Hier ist ein allgemeiner speichereffiziente Lösung, um die letzten ‚n‘ Zeilen ermöglicht übersprungen werden (wie der head Befehl):

import collections, fileinput 
def head(filename, lines_to_delete=1): 
    queue = collections.deque() 
    lines_to_delete = max(0, lines_to_delete) 
    for line in fileinput.input(filename, inplace=True, backup='.bak'): 
     queue.append(line) 
     if lines_to_delete == 0: 
      print queue.popleft(), 
     else: 
      lines_to_delete -= 1 
    queue.clear() 
50

Da ich routinemäßig mit vielen Gigabyte Dateien arbeite, funktionierte das Durchschleifen wie in den Antworten erwähnt nicht für mich. Die Lösung, die ich verwende:

file = open(sys.argv[1], "r+", encoding = "utf-8") 

#Move the pointer (similar to a cursor in a text editor) to the end of the file. 
file.seek(0, os.SEEK_END) 

#This code means the following code skips the very last character in the file - 
#i.e. in the case the last line is null we delete the last line 
#and the penultimate one 
pos = file.tell() - 1 

#Read each character in the file one at a time from the penultimate 
#character going backwards, searching for a newline character 
#If we find a new line, exit the search 
while pos > 0 and file.read(1) != "\n": 
    pos -= 1 
    file.seek(pos, os.SEEK_SET) 

#So long as we're not at the start of the file, delete all the characters ahead of this position 
if pos > 0: 
    file.seek(pos, os.SEEK_SET) 
    file.truncate() 

file.close() 
+3

das ist die beste Antwort. Verwenden Sie "mit" Anweisung, um eine Zeile zu speichern :) – cppython

+0

Sehr schön gemacht. Sehr C-ähnlich. –

+1

Ich stieß auf einige Kompatibilitätsprobleme (mit Py3) bei der Verwendung dieser Methode für Dateien, die auf Mac und Windows verwendet wurden, weil intern Mac einen anderen Zeilenabschluss als Windows verwendet (die 2: cr und lf verwendet). Die Lösung bestand darin, die Datei im binären Lesemodus ("rb +") zu öffnen und nach dem binären Zeilenvorschubzeichen b "\ n" zu suchen. – JrtPec

0

hier meine Lösung für Linux-Anwender ist:

import os 
file_path = 'test.txt' 
os.system('sed -i "$ d" {0}'.format(file_path)) 

keine Notwendigkeit, zu lesen und durch die Datei in Python durchlaufen.

1

Inspirierende aus früheren Posts, ich vortragen dies:

with open('file_name', 'r+') as f: 
    f.seek(0, os.SEEK_END) 
    while f.tell() and f.read(1) != '\n': 
    f.seek(-2, os.SEEK_CUR) 
    f.truncate()