2010-07-05 21 views
2

Disons que j'ai fichier/etc/conf1Comment puis-je modifier un fichier et écrire uniquement les modifications sur le disque - essentiellement, sed (python)?

son contenu sont le long des lignes de

option = banana 
name = monkey 
operation = eat 

et disons que je veux remplacer « singe » par « autruche ». Comment puis-je faire cela sans lire le fichier en mémoire, en le modifiant et en le réécrivant tout simplement? Fondamentalement, comment puis-je modifier le fichier "en place"?

+1

Difficulté. Que pensez-vous que vous feriez en modifiant "en place"? Est-ce un gros dossier et vous avez peur de le garder en mémoire? – MattH

+0

Je pense que vous ne pouvez pas si vous voulez changer la taille du fichier. De plus, 'sed' ne peut pas faire cela, il n'est tout simplement pas supporté par les systèmes d'exploitation actuels. Comme alternative, vous pouvez regarder dans le module 'ConfigParser' pour analyser les fichiers de configuration de type INI. – Philipp

+0

Dans le cas présent, il s'agit plus d'un hypothétique "quelles sont les chances de moi lire un fichier, le modifier, l'écrire et avoir un problème à mi-chemin et se retrouver avec un fichier corrompu?" problème. J'ai pensé à une approche "lire conf1, modifier, écrire à conf1.temp, mv conf1.temp conf1", mais je pensais qu'il pourrait y avoir une façon plus élégante de le faire. En place, mod serait cool. – Neoscopio

Répondre

1

Vous devriez regarder le module fileinput:

http://docs.python.org/library/fileinput.html

Il y a une option pour effectuer inplace édition via la méthode d'entrée:

http://docs.python.org/library/fileinput.html#fileinput.input

MISE À JOUR - exemple de code:

 

import fileinput 
import re 
import sys 

for line in fileinput.input(inplace=True): 
    sys.stdout.write(re.sub(r'monkey', 'ostrich', line)) 
 

Utilisation de sys.stdout.write pour ne pas ajouter de retour chariot.

+0

Essayé, ne pouvait pas le faire fonctionner. Le fait que fileinput existe est la raison pour laquelle je pose cette question. Pouvez-vous élaborer ou donner un exemple s'il vous plaît? – Neoscopio

+0

J'ai ajouté un exemple de code maintenant. NB: techniquement, il lit le fichier en mémoire (une ligne à la fois), mais cela équivaut à la façon dont sed fonctionne de toute façon. L'élément clé est que vous devez sortir la ligne même si vous ne l'avez pas modifiée. –

2

Vous ne pouvez pas. "autruche" est une lettre de plus que "singe", donc vous devrez réécrire le fichier au moins à partir de ce point. Les systèmes de fichiers ne prennent pas en charge le "déplacement" du contenu du fichier vers le haut ou vers le bas.

Si c'est juste un petit fichier, il n'y a aucune raison de déranger même avec cela, et vous pourriez aussi bien réécrire le fichier entier.

S'il s'agit d'un fichier très volumineux, vous devrez reconsidérer la conception interne du contenu du fichier, par exemple, avec une approche par blocs.

+0

C'est quelque chose qui m'a dérangé pendant un certain temps et je ne pourrais jamais comprendre comment faire ceci. Je pensais juste que je aspirais à manipuler des fichiers. En fait, j'ai déjà implémenté l'approche "lire, modifier, écrire en bloc" il y a quelque temps en python et on m'a dit que c'était une chose stupide à faire parce que f.read(), le système ne charge réellement que quelques blocs à un temps ... et oui, c'était un gros fichier (100 Mo de large). – Neoscopio

0

Cela dépend de ce que vous entendez par "en place". Comment pouvez-vous le faire si vous voulez remplacer monkey par supercalifragilisticexpialidocious? Voulez-vous remplacer le fichier restant? Si ce n'est pas le cas, vous devrez lire à l'avance et déplacer les contenus ultérieurs du fichier vers l'avant.

+0

Shifting est plus cher que d'écrire un nouveau fichier, ressources, je suppose? – Neoscopio

0

Les instructions de l'UC fonctionnent sur des données provenant de la mémoire.

La partie du fichier que vous souhaitez lire doit être en mémoire avant de pouvoir être lue; Avant d'écrire quoi que ce soit sur le disque, cette information doit être en mémoire.

Le fichier entier n'a pas besoin d'être là à la fois, mais pour faire une recherche-remplacer sur un fichier entier, chaque caractère du fichier passera par la RAM à un moment donné.

Ce que vous cherchez probablement, c'est quelque chose comme l'appel système mmap(). Le module d'entrée de fichier ci-dessus sonne comme une chose plausible à utiliser.

+0

Si vous ne faites qu'analyser jusqu'à ce que vous atteigniez l'option de configuration souhaitée, vous lisez uniquement le fichier entier dans le pire des cas. Mon problème était lié au déplacement du contenu du fichier, je suppose ... – Neoscopio

0

Les modifications sur place ne sont faciles que si vous ne modifiez pas la taille du fichier ou si vous ne vous y attelez. L'exemple suivant remplace le premier octet du fichier par un « un » caractère:

fd = os.open("...", os.O_WRONLY | os.O_CREAT) 
os.write(fd, "a") 
os.close(fd) 

Notez que les objets file Python ne supporte pas, vous devez utiliser les fonctions de bas niveau. Pour l'ajouter, ouvrez le fichier avec la fonction open() en mode "a".

+0

C'est ce que j'ai toujours supposé ... merci. – Neoscopio

+0

'fp = open (" ... "," r + b "); fp.write ("a"); fp.close() 'Maintenant, est-ce que je vous ai mal compris quand vous avez dit" Les objets 'file' de Python ne supportent pas cela"? – tzot

0

sed -i.bak '/monkey$/newword/' file

+0

... en python, sans sed, sous-processus, os.system ou similaire: D – Neoscopio