web-dev-qa-db-fra.com

Supprimer la dernière ligne du fichier avec python

Comment peut-on supprimer la toute dernière ligne d'un fichier avec python?

Exemple de fichier d'entrée:

hello
world
foo
bar

Exemple de fichier de sortie:

hello
world
foo

J'ai créé le code suivant pour trouver le nombre de lignes dans le fichier - mais je ne sais pas comment supprimer le numéro de ligne spécifique. Je suis nouveau sur Python - donc s'il y a un moyen plus facile - dites-le moi s'il vous plaît.

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

MODIFIER:

Je l'ai compris en utilisant une variété de réponses: principalement Strawberry's et quelque chose que j'ai vu sur le Web (désolé, je ne trouve pas le lien).

#!/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()
28
torger

Vous pouvez utiliser le code ci-dessus et ensuite: -

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

Cela vous donnerait un tableau de lignes contenant toutes les lignes sauf la dernière.

9
Martin

Parce que je travaille régulièrement avec des fichiers de plusieurs gigaoctets, la lecture en boucle, comme indiqué dans les réponses, ne m'a pas fonctionné. La solution que j'utilise:

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()
60
Saqib

Cela n'utilise pas python, mais python est le mauvais outil pour le travail s'il s'agit de la seule tâche que vous souhaitez. Vous pouvez utiliser l'utilitaire standard * nix head et exécuter

head -n-1 filename > newfile

qui va copier tout le fichier sauf la dernière ligne dans newfile.

6
Peter

En supposant que vous deviez le faire en Python et que vous ayez un fichier suffisamment grand pour que le découpage de la liste ne soit pas suffisant, vous pouvez le faire en un seul passage sur le fichier:

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

Ce n'est pas le code le plus élégant au monde, mais il fait le travail.

Fondamentalement, il met en mémoire tampon chaque ligne d'un fichier par le biais de la variable last_line, chaque itération génère la ligne d'itérations précédente.

4
Dan Head

Sur les systèmes où file.truncate () fonctionne, vous pouvez faire quelque chose comme ceci:

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)

Selon mes tests, file.tell () ne fonctionne pas lors de la lecture ligne par ligne, probablement à cause de la mise en mémoire tampon de la confusion. C'est pourquoi cela ajoute la longueur des lignes pour déterminer les positions. Notez que cela ne fonctionne que sur les systèmes où le délimiteur de ligne se termine par '\ n'.

3
Laurence Gonsalves

voici ma solution pour les utilisateurs de Linux:

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

pas besoin de lire et de parcourir le fichier en python. 

1
Moj

Inspirant des articles précédents, je propose ceci:

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()
1

voici une autre façon, sans mettre en mémoire le fichier entier

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

Voici une solution plus efficace en termes de mémoire permettant de sauter les dernières lignes (comme la commande head):

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()
0
Ned Deily

Bien que je ne l'ait pas testé (s'il vous plaît, aucune haine pour cela), je crois qu'il existe un moyen plus rapide de le faire. C'est plus une solution C, mais tout à fait possible en Python. Ce n'est pas Pythonic non plus. C'est une théorie, je dirais.

Tout d’abord, vous devez connaître le codage du fichier. Définissez une variable sur le nombre d'octets utilisés par un caractère dans l'encodage (1 octet en ASCII). CHARsize (pourquoi pas). Il s'agira probablement d'un octet avec un fichier ASCII. 

Saisissez ensuite la taille du fichier, définissez FILEsize

Supposons que vous avez l'adresse du fichier (en mémoire) dans FILEadd

Ajouter FILEsize to FILEadd

Déplacez les mots de passe (incrément de -1 *** CHARsize **), en testant chaque octet de CHARsize pour un\n (ou la nouvelle ligne utilisée par votre système). Lorsque vous atteignez la première\n, vous avez maintenant la position du début de la première ligne du fichier. Remplacez\n par\x1a (26, le ASCII pour EOF, ou quel que soit le système/votre système, avec le codage). 

Nettoyez comme vous le souhaitez (changez la taille du fichier, touchez le fichier). 

Si cela fonctionne comme je le suppose, cela vous fera gagner beaucoup de temps, car vous n'avez pas besoin de lire l'intégralité du fichier depuis le début, vous lisez depuis la fin. 

0
Isaac