Essayez fileinputcomme décrit par @ jf-sebastian ici . Il semble vous permettre de travailler ligne par ligne, via un fichier temporaire, le tout avec une forsyntaxe simple .
Kevin le
Réponses:
205
Tout d'abord, ouvrez le fichier et récupérez toutes vos lignes du fichier. Ensuite, rouvrez le fichier en mode écriture et réécrivez vos lignes, à l'exception de la ligne que vous souhaitez supprimer:
with open("yourfile.txt","r")as f:
lines = f.readlines()with open("yourfile.txt","w")as f:for line in lines:if line.strip("\n")!="nickname_to_delete":
f.write(line)
Vous avez besoin strip("\n")du caractère de nouvelle ligne dans la comparaison car si votre fichier ne se termine pas par un caractère de nouvelle ligne, le tout dernier linene le sera pas non plus.
pourquoi devons-nous l'ouvrir et le fermer deux fois?
Ooker
3
@Ooker: Vous devez ouvrir le fichier deux fois (et le fermer entre les deux) car dans le premier mode, il est en "lecture seule" car vous ne faites que lire les lignes actuelles du fichier. Vous le fermez ensuite et le rouvrez en "mode écriture", où le fichier est inscriptible et vous remplacez le contenu du fichier sans la ligne que vous vouliez supprimer.
Devin
4
Pourquoi Python ne nous permet-il pas de faire cela en une seule ligne?
Ooker
5
@Ooker, lorsque vous lisez une ligne, essayez d'imaginer un curseur se déplaçant le long de la ligne pendant sa lecture. Une fois que cette ligne a été lue, le curseur la dépasse. Lorsque vous essayez d'écrire dans le fichier, vous écrivez là où se trouve actuellement le curseur. En rouvrant le fichier, vous réinitialisez le curseur.
Waddas
4
Utilisez le avec composé!
Sceluswe
101
Solution à ce problème avec une seule ouverture:
with open("target.txt","r+")as f:
d = f.readlines()
f.seek(0)for i in d:if i !="line you want to remove...":
f.write(i)
f.truncate()
Cette solution ouvre le fichier en mode r / w ("r +") et utilise seek pour réinitialiser le pointeur f puis tronquer pour tout supprimer après la dernière écriture.
Cela a très bien fonctionné pour moi, car je devais également utiliser lockfile (fcntl). Je n'ai trouvé aucun moyen d'utiliser fileinput avec fcntl.
Easyrider
1
Ce serait bien de voir certains effets secondaires de cette solution.
user1767754
3
Je ne ferais pas ça. Si vous obtenez une erreur dans la forboucle, vous vous retrouverez avec un fichier partiellement écrasé, avec des lignes en double ou une ligne à moitié coupée. Vous voudrez peut-être f.truncate()juste après à la f.seek(0)place. De cette façon, si vous obtenez une erreur, vous vous retrouverez avec un fichier incomplet. Mais la vraie solution (si vous avez l'espace disque) est de sortir dans un fichier temporaire puis de l'utiliser os.replace()ou pathlib.Path(temp_filename).replace(original_filename)de l'échanger avec l'original une fois que tout a réussi.
Boris
Pouvez-vous ajouter i.strip('\n') != "line you want to remove..."comme mentionné dans la réponse acceptée, cela résoudrait parfaitement mon problème. Parce que je in'ai rien fait pour moi
Mangohero1
31
La meilleure et la plus rapide option, plutôt que de tout stocker dans une liste et de rouvrir le fichier pour l'écrire, est à mon avis de réécrire le fichier ailleurs.
with open("yourfile.txt","r")as input:with open("newfile.txt","w")as output:for line in input:if line.strip("\n")!="nickname_to_delete":
output.write(line)
C'est tout! Dans une boucle et une seule, vous pouvez faire la même chose. Ce sera beaucoup plus rapide.
Au lieu d'utiliser la boucle for normale, nous pouvons utiliser l' expression du générateur. De cette façon, le programme ne chargera pas toutes les lignes du fichier vers la mémoire, ce qui n'est pas une bonne idée dans le cas de gros fichiers. Il n'aura qu'une seule ligne en mémoire à la fois. Avec l'expression du générateur, la boucle ressemblera à,(output.write(line) for line in input if line!="nickname_to_delete"+"\n")
shrishinde
4
@ShriShinde Vous ne lisez pas non plus le fichier en mémoire lors de la boucle sur l'objet fichier, donc cette solution fonctionne de la même manière que votre suggestion.
Steinar Lima le
Vous voudrez peut-être supprimer le fichier d'origine et renommer le deuxième fichier avec le nom du fichier d'origine, qui avec Python sur un système d'exploitation Linux ressemblerait à ceci,subprocess.call(['mv', 'newfile.txt', 'yourfile.txt'])
Max
6
os.replace(nouveau dans python v 3.3) est plus multiplateforme qu'un appel système mv.
7yl4r
Simple et génial.
JuBaer AD
27
C'est une "fourchette" de la réponse de @Lother (qui, je crois, devrait être considérée comme la bonne réponse).
Pour un fichier comme celui-ci:
$ cat file.txt
1: october rust
2: november rain
3: december snow
Cette fourchette de la solution de Lother fonctionne bien:
#!/usr/bin/python3.4with open("file.txt","r+")as f:
new_f = f.readlines()
f.seek(0)for line in new_f:if"snow"notin line:
f.write(line)
f.truncate()
Améliorations:
with open, qui rejette l'utilisation de f.close()
plus clair if/elsepour évaluer si la chaîne n'est pas présente dans la ligne courante
@yifan oui. Sinon, au lieu d'écraser le fichier, vous ajouterez le fichier à lui-même (sans les lignes que vous excluez).
Boris
5
Le problème avec la lecture des lignes au premier passage et les modifications (suppression de lignes spécifiques) au second passage est que si la taille de vos fichiers est énorme, vous manquerez de RAM. Au lieu de cela, une meilleure approche consiste à lire les lignes, une par une, et à les écrire dans un fichier séparé, en éliminant celles dont vous n'avez pas besoin. J'ai utilisé cette approche avec des fichiers de 12 à 50 Go et l'utilisation de la RAM reste presque constante. Seuls les cycles CPU indiquent le traitement en cours.
Cette solution n'est pas indépendante du système d'exploitation, et comme OP n'a pas spécifié de système d'exploitation, il n'y a aucune raison de publier une réponse spécifique à Linux imo.
Steinar Lima
2
Quiconque suggère d'utiliser un sous-processus pour tout ce qui peut être fait avec juste python obtient un vote négatif! Et +1 à @SteinarLima ... Je suis d'accord
Jamie Lindsey
2
Je pense que si vous lisez le fichier dans une liste, vous pouvez parcourir la liste pour rechercher le surnom dont vous souhaitez vous débarrasser. Vous pouvez le faire beaucoup plus efficacement sans créer de fichiers supplémentaires, mais vous devrez réécrire le résultat dans le fichier source.
Voici comment je pourrais faire ceci:
import, os, csv # and other imports you need
nicknames_to_delete =['Nick','Stephen','Mark']
Je suppose que nicknames.csvcontient des données telles que:
Ensuite, parcourez la liste pour faire correspondre vos entrées à supprimer:
for nick in nicknames_to_delete:try:if nick in nicknames:
nicknames.pop(nicknames.index(nick))else:print(nick +" is not found in the file")exceptValueError:pass
Enfin, écrivez le résultat dans le fichier:
with open("nicknames.csv","a")as nicknamesFile:
nicknamesFile.seek(0)
nicknamesFile.truncate()
nicknamesWriter = csv.writer(nicknamesFile)for name in nicknames:
nicknamesWriter.writeRow([str(name)])
nicknamesFile.close()
En général, vous ne pouvez pas; vous devez réécrire le fichier entier (au moins du point de modification à la fin).
Dans certains cas spécifiques, vous pouvez faire mieux que cela -
si tous vos éléments de données sont de la même longueur et dans aucun ordre spécifique, et que vous connaissez le décalage de celui dont vous souhaitez vous débarrasser, vous pouvez copier le dernier élément sur celui à supprimer et tronquer le fichier avant le dernier élément ;
ou vous pouvez simplement écraser le bloc de données avec une valeur `` ce sont des données incorrectes, les ignorer '' ou conserver un indicateur `` cet élément a été supprimé '' dans vos éléments de données enregistrés de sorte que vous puissiez le marquer comme supprimé sans autrement modifier le fichier.
C'est probablement exagéré pour les documents courts (quelque chose de moins de 100 Ko?).
Vous avez probablement déjà une bonne réponse, mais voici la mienne. Au lieu d'utiliser une liste pour collecter des données non filtrées (quelle readlines()méthode fait), j'utilise deux fichiers. Le premier est destiné à contenir les données principales et le second à filtrer les données lorsque vous supprimez une chaîne spécifique. Voici un code:
main_file = open('data_base.txt').read()# your main dataBase file
filter_file = open('filter_base.txt','w')
filter_file.write(main_file)
filter_file.close()
main_file = open('data_base.txt','w')for line in open('filter_base'):if'your data to delete'notin line:# remove a specific string
main_file.write(line)# put all strings back to your db except deletedelse:pass
main_file.close()
Enregistrez les lignes de fichier dans une liste, puis supprimez de la liste la ligne que vous souhaitez supprimer et écrivez les lignes restantes dans un nouveau fichier
with open("file_name.txt","r")as f:
lines = f.readlines()
lines.remove("Line you want to delete\n")with open("new_file.txt","w")as new_f:for line in lines:
new_f.write(line)
Si votre fichier ne se termine pas par une nouvelle ligne, ce code ne supprimera pas la dernière ligne même si elle contient un mot que vous souhaitez supprimer.
Boris
0
voici une autre méthode pour supprimer une / des ligne (s) d'un fichier:
src_file = zzzz.txt
f = open(src_file,"r")
contents = f.readlines()
f.close()
contents.pop(idx)# remove the line item from list, by line number, starts from 0
f = open(src_file,"w")
contents ="".join(contents)
f.write(contents)
f.close()
En supposant que vous puissiez charger votre fichier txt complet. Vous définissez ensuite une liste de surnoms indésirables, puis vous les remplacez par une chaîne vide "".
# Delete unwanted charactersimport re
# Read, then decode for py2 compat.
path_to_file ='data/nicknames.txt'
text = open(path_to_file,'rb').read().decode(encoding='utf-8')# Define unwanted nicknames and substitute them
unwanted_nickname_list =['SourDough']
text = re.sub("|".join(unwanted_nickname_list),"", text)
il n'est pas nécessaire de créer un dict, il suffit d'utiliserfor nb, line in enumerate(f.readlines())
Dionys
-3
Prenez le contenu du fichier, divisez-le par nouvelle ligne en un tuple. Ensuite, accédez au numéro de ligne de votre tuple, joignez votre tuple de résultat et écrasez-le dans le fichier.
(1) voulez-vous dire tuple(f.read().split('\n'))?? (2) "accéder au numéro de ligne de votre tuple" et "joindre votre tuple résultat" semblent plutôt mystérieux; le code Python réel pourrait être plus compréhensible.
fileinput
comme décrit par @ jf-sebastian ici . Il semble vous permettre de travailler ligne par ligne, via un fichier temporaire, le tout avec unefor
syntaxe simple .Réponses:
Tout d'abord, ouvrez le fichier et récupérez toutes vos lignes du fichier. Ensuite, rouvrez le fichier en mode écriture et réécrivez vos lignes, à l'exception de la ligne que vous souhaitez supprimer:
Vous avez besoin
strip("\n")
du caractère de nouvelle ligne dans la comparaison car si votre fichier ne se termine pas par un caractère de nouvelle ligne, le tout dernierline
ne le sera pas non plus.la source
Solution à ce problème avec une seule ouverture:
Cette solution ouvre le fichier en mode r / w ("r +") et utilise seek pour réinitialiser le pointeur f puis tronquer pour tout supprimer après la dernière écriture.
la source
for
boucle, vous vous retrouverez avec un fichier partiellement écrasé, avec des lignes en double ou une ligne à moitié coupée. Vous voudrez peut-êtref.truncate()
juste après à laf.seek(0)
place. De cette façon, si vous obtenez une erreur, vous vous retrouverez avec un fichier incomplet. Mais la vraie solution (si vous avez l'espace disque) est de sortir dans un fichier temporaire puis de l'utiliseros.replace()
oupathlib.Path(temp_filename).replace(original_filename)
de l'échanger avec l'original une fois que tout a réussi.i.strip('\n') != "line you want to remove..."
comme mentionné dans la réponse acceptée, cela résoudrait parfaitement mon problème. Parce que jei
n'ai rien fait pour moiLa meilleure et la plus rapide option, plutôt que de tout stocker dans une liste et de rouvrir le fichier pour l'écrire, est à mon avis de réécrire le fichier ailleurs.
C'est tout! Dans une boucle et une seule, vous pouvez faire la même chose. Ce sera beaucoup plus rapide.
la source
(output.write(line) for line in input if line!="nickname_to_delete"+"\n")
subprocess.call(['mv', 'newfile.txt', 'yourfile.txt'])
os.replace
(nouveau dans python v 3.3) est plus multiplateforme qu'un appel systèmemv
.C'est une "fourchette" de la réponse de @Lother (qui, je crois, devrait être considérée comme la bonne réponse).
Pour un fichier comme celui-ci:
Cette fourchette de la solution de Lother fonctionne bien:
Améliorations:
with open
, qui rejette l'utilisation def.close()
if/else
pour évaluer si la chaîne n'est pas présente dans la ligne courantela source
Le problème avec la lecture des lignes au premier passage et les modifications (suppression de lignes spécifiques) au second passage est que si la taille de vos fichiers est énorme, vous manquerez de RAM. Au lieu de cela, une meilleure approche consiste à lire les lignes, une par une, et à les écrire dans un fichier séparé, en éliminant celles dont vous n'avez pas besoin. J'ai utilisé cette approche avec des fichiers de 12 à 50 Go et l'utilisation de la RAM reste presque constante. Seuls les cycles CPU indiquent le traitement en cours.
la source
J'ai aimé l'approche d'entrée de fichier comme expliqué dans cette réponse: Suppression d'une ligne d'un fichier texte (python)
Disons par exemple que j'ai un fichier contenant des lignes vides et que je souhaite supprimer les lignes vides, voici comment je l'ai résolu:
la source
Si vous utilisez Linux, vous pouvez essayer l'approche suivante.
Supposons que vous ayez un fichier texte nommé
animal.txt
:Supprimez la première ligne:
puis
la source
Je pense que si vous lisez le fichier dans une liste, vous pouvez parcourir la liste pour rechercher le surnom dont vous souhaitez vous débarrasser. Vous pouvez le faire beaucoup plus efficacement sans créer de fichiers supplémentaires, mais vous devrez réécrire le résultat dans le fichier source.
Voici comment je pourrais faire ceci:
Je suppose que
nicknames.csv
contient des données telles que:Ensuite, chargez le fichier dans la liste:
Ensuite, parcourez la liste pour faire correspondre vos entrées à supprimer:
Enfin, écrivez le résultat dans le fichier:
la source
En général, vous ne pouvez pas; vous devez réécrire le fichier entier (au moins du point de modification à la fin).
Dans certains cas spécifiques, vous pouvez faire mieux que cela -
si tous vos éléments de données sont de la même longueur et dans aucun ordre spécifique, et que vous connaissez le décalage de celui dont vous souhaitez vous débarrasser, vous pouvez copier le dernier élément sur celui à supprimer et tronquer le fichier avant le dernier élément ;
ou vous pouvez simplement écraser le bloc de données avec une valeur `` ce sont des données incorrectes, les ignorer '' ou conserver un indicateur `` cet élément a été supprimé '' dans vos éléments de données enregistrés de sorte que vous puissiez le marquer comme supprimé sans autrement modifier le fichier.
C'est probablement exagéré pour les documents courts (quelque chose de moins de 100 Ko?).
la source
Vous avez probablement déjà une bonne réponse, mais voici la mienne. Au lieu d'utiliser une liste pour collecter des données non filtrées (quelle
readlines()
méthode fait), j'utilise deux fichiers. Le premier est destiné à contenir les données principales et le second à filtrer les données lorsque vous supprimez une chaîne spécifique. Voici un code:J'espère que vous trouverez cela utile! :)
la source
Enregistrez les lignes de fichier dans une liste, puis supprimez de la liste la ligne que vous souhaitez supprimer et écrivez les lignes restantes dans un nouveau fichier
la source
voici une autre méthode pour supprimer une / des ligne (s) d'un fichier:
la source
J'aime cette méthode utilisant fileinput et la méthode 'inplace':
C'est un peu moins verbeux que les autres réponses et c'est assez rapide pour
la source
En supposant que vous puissiez charger votre fichier txt complet. Vous définissez ensuite une liste de surnoms indésirables, puis vous les remplacez par une chaîne vide "".
la source
Pour supprimer une ligne spécifique d'un fichier par son numéro de ligne :
Remplacez les variables filename et line_to_delete par le nom de votre fichier et le numéro de ligne que vous souhaitez supprimer.
Exemple de sortie :
la source
for nb, line in enumerate(f.readlines())
Prenez le contenu du fichier, divisez-le par nouvelle ligne en un tuple. Ensuite, accédez au numéro de ligne de votre tuple, joignez votre tuple de résultat et écrasez-le dans le fichier.
la source
tuple(f.read().split('\n'))
?? (2) "accéder au numéro de ligne de votre tuple" et "joindre votre tuple résultat" semblent plutôt mystérieux; le code Python réel pourrait être plus compréhensible.