102 votes

Insérer une ligne au milieu d'un fichier avec Python ?

Existe-t-il un moyen de le faire ? Disons que j'ai un fichier qui est une liste de noms qui se présente comme suit :

  1. Alfred
  2. Projet de loi
  3. Donald

Comment puis-je insérer le troisième nom, "Charlie", à la ligne x (dans ce cas 3), et envoyer automatiquement tous les autres sur une ligne ? J'ai vu d'autres questions de ce type, mais elles n'ont pas reçu de réponses utiles. Est-ce possible, de préférence avec une méthode ou une boucle ?

130voto

martincho Points 1207

Il s'agit d'une façon de procéder.

with open("path_to_file", "r") as f:
    contents = f.readlines()

contents.insert(index, value)

with open("path_to_file", "w") as f:
    contents = "".join(contents)
    f.write(contents)

index y value sont la ligne et la valeur de votre choix, les lignes commençant à 0.

41voto

DavidS Points 1657

Si vous souhaitez rechercher une sous-chaîne dans un fichier et ajouter un nouveau texte à la ligne suivante, l'une des méthodes les plus élégantes est la suivante :

import fileinput
for line in fileinput.FileInput(file_path,inplace=1):
    if "TEXT_TO_SEARCH" in line:
        line=line.replace(line,line+"NEW_TEXT")
    print line,

13voto

TemporalWolf Points 4899

Il existe une combinaison de techniques que j'ai trouvée utile pour résoudre ce problème :

with open(file, 'r+') as fd:
    contents = fd.readlines()
    contents.insert(index, new_string)  # new_string should end in a newline
    fd.seek(0)  # readlines consumes the iterator, so we need to start over
    fd.writelines(contents)  # No need to truncate as we are increasing filesize

Dans notre application particulière, nous voulions l'ajouter après une certaine chaîne de caractères :

with open(file, 'r+') as fd:
    contents = fd.readlines()
    if match_string in contents[-1]:  # Handle last line to prevent IndexError
        contents.append(insert_string)
    else:
        for index, line in enumerate(contents):
            if match_string in line and insert_string not in contents[index + 1]:
                contents.insert(index + 1, insert_string)
                break
    fd.seek(0)
    fd.writelines(contents)

Si vous souhaitez qu'il insère la chaîne après chaque occurrence de la correspondance, au lieu de la première seulement, supprimez l'attribut else: (et correctement désindenté) et le break .

Il convient également de noter que le and insert_string not in contents[index + 1]: l'empêche d'ajouter plus d'une copie après le match_string Il est donc possible de l'exécuter plusieurs fois en toute sécurité.

9voto

Sean Points 161

La réponse acceptée consiste à charger l'intégralité du fichier en mémoire, ce qui ne fonctionne pas très bien pour les fichiers volumineux. La solution suivante écrit le contenu du fichier avec les nouvelles données insérées dans la bonne ligne dans un fichier temporaire dans le même répertoire (donc sur le même système de fichiers), en ne lisant que de petits morceaux du fichier source à la fois. Elle écrase ensuite le fichier source avec le contenu du fichier temporaire dans un fichier efficace (Python 3.8+).

from pathlib import Path
from shutil import copyfile
from tempfile import NamedTemporaryFile

sourcefile = Path("/path/to/source").resolve()
insert_lineno = 152  # The line to insert the new data into.
insert_data = "..."  # Some string to insert.

with sourcefile.open(mode="r") as source:
    destination = NamedTemporaryFile(mode="w", dir=str(sourcefile.parent))
    lineno = 1

    while lineno < insert_lineno:
        destination.file.write(source.readline())
        lineno += 1

    # Insert the new data.
    destination.file.write(insert_data)

    # Write the rest in chunks.
    while True:
        data = source.read(1024)
        if not data:
            break
        destination.file.write(data)

# Finish writing data.
destination.flush()
# Overwrite the original file's contents with that of the temporary file.
# This uses a memory-optimised copy operation starting from Python 3.8.
copyfile(destination.name, str(sourcefile))
# Delete the temporary file.
destination.close()

ÉDITER 2020-09-08 : Je viens de trouver une réponse sur l'examen du code qui fait quelque chose de similaire à ce qui précède avec plus d'explications - cela pourrait être utile à certains.

7voto

jordanm Points 6490

Il suffit de lire les données dans une liste et d'insérer le nouvel enregistrement à l'endroit voulu.

names = []
with open('names.txt', 'r+') as fd:
    for line in fd:
        names.append(line.split(' ')[-1].strip())

    names.insert(2, "Charlie") # element 2 will be 3. in your list
    fd.seek(0)
    fd.truncate()

    for i in xrange(len(names)):
        fd.write("%d. %s\n" %(i + 1, names[i]))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X