J'utilise Python et je souhaite insérer une chaîne dans un fichier texte sans supprimer ni copier le fichier. Comment puis je faire ça?
J'utilise Python et je souhaite insérer une chaîne dans un fichier texte sans supprimer ni copier le fichier. Comment puis je faire ça?
Réponses:
Malheureusement, il n'y a aucun moyen d'insérer au milieu d'un fichier sans le réécrire. Comme les affiches précédentes l'ont indiqué, vous pouvez ajouter à un fichier ou en écraser une partie en utilisant la recherche, mais si vous voulez ajouter des éléments au début ou au milieu, vous devrez le réécrire.
C'est une chose du système d'exploitation, pas une chose de Python. C'est la même chose dans toutes les langues.
Ce que je fais habituellement, c'est lire à partir du fichier, apporter les modifications et l'écrire dans un nouveau fichier appelé myfile.txt.tmp ou quelque chose comme ça. C'est mieux que de lire le fichier entier en mémoire car le fichier peut être trop volumineux pour cela. Une fois le fichier temporaire terminé, je le renomme de la même manière que le fichier d'origine.
C'est un bon moyen sûr de le faire, car si l'écriture du fichier se bloque ou s'interrompt pour une raison quelconque, vous avez toujours votre fichier d'origine intact.
Tout dépends de ce que tu veux faire. Pour ajouter, vous pouvez l'ouvrir avec "a":
with open("foo.txt", "a") as f:
f.write("new line\n")
Si vous voulez préprendre quelque chose, vous devez d'abord lire le fichier:
with open("foo.txt", "r+") as f:
old = f.read() # read everything in the file
f.seek(0) # rewind
f.write("new line\n" + old) # write the new line before
with
instruction dans Python 2.5, vous devez ajouter "from future import with_statement". En dehors de cela, l'ouverture de fichiers avec l' with
instruction est certainement plus lisible et moins sujette aux erreurs que la fermeture manuelle.
fileinput
bibliothèque d'aide avec des manipulations de la routine dirty open / read / modify / write / replace bien lorsque vous utilisez inline=True
arg. Exemple ici: stackoverflow.com/a/2363893/47390
f.Close()
Le fileinput
module de la bibliothèque standard Python réécrira un fichier en place si vous utilisez le paramètre inplace = 1:
import sys
import fileinput
# replace all occurrences of 'sit' with 'SIT' and insert a line after the 5th
for i, line in enumerate(fileinput.input('lorem_ipsum.txt', inplace=1)):
sys.stdout.write(line.replace('sit', 'SIT')) # replace 'sit' and write
if i == 4: sys.stdout.write('\n') # write a blank line after the 5th line
La réécriture d'un fichier sur place se fait souvent en enregistrant l'ancienne copie avec un nom modifié. Les gens d'Unix ajoutent un ~
pour marquer l'ancien. Les gens de Windows font toutes sortes de choses - ajoutez .bak ou .old - ou renommez le fichier entièrement ou mettez le ~ au début du nom.
import shutil
shutil.move( afile, afile+"~" )
destination= open( aFile, "w" )
source= open( aFile+"~", "r" )
for line in source:
destination.write( line )
if <some condition>:
destination.write( >some additional line> + "\n" )
source.close()
destination.close()
Au lieu de shutil
, vous pouvez utiliser ce qui suit.
import os
os.rename( aFile, aFile+"~" )
os.rename(aFile, aFile + "~")
modifiera le nom du fichier source, sans créer de copie.
Le module mmap de Python vous permettra d'insérer dans un fichier. L'exemple suivant montre comment cela peut être fait sous Unix (Windows mmap peut être différent). Notez que cela ne gère pas toutes les conditions d'erreur et que vous risquez de corrompre ou de perdre le fichier d'origine. De plus, cela ne gérera pas les chaînes Unicode.
import os
from mmap import mmap
def insert(filename, str, pos):
if len(str) < 1:
# nothing to insert
return
f = open(filename, 'r+')
m = mmap(f.fileno(), os.path.getsize(filename))
origSize = m.size()
# or this could be an error
if pos > origSize:
pos = origSize
elif pos < 0:
pos = 0
m.resize(origSize + len(str))
m[pos+len(str):] = m[pos:origSize]
m[pos:pos+len(str)] = str
m.close()
f.close()
Il est également possible de le faire sans mmap avec des fichiers ouverts en mode `` r + '', mais c'est moins pratique et moins efficace car vous auriez à lire et à stocker temporairement le contenu du fichier de la position d'insertion à EOF - ce qui pourrait être énorme.
Comme mentionné par Adam, vous devez prendre en compte les limitations de votre système avant de pouvoir décider si vous avez suffisamment de mémoire pour tout lire en mémoire, remplacez-en des parties et réécrivez-le.
Si vous avez affaire à un petit fichier ou que vous n'avez pas de problèmes de mémoire, cela peut aider:
Option 1) Lire le fichier entier en mémoire, faire une substitution regex sur tout ou partie de la ligne et le remplacer par cette ligne plus la ligne supplémentaire. Vous devrez vous assurer que la «ligne médiane» est unique dans le fichier ou si vous avez des horodatages sur chaque ligne, cela devrait être assez fiable.
# open file with r+b (allow write and binary mode)
f = open("file.log", 'r+b')
# read entire content of file into memory
f_content = f.read()
# basically match middle line and replace it with itself and the extra line
f_content = re.sub(r'(middle line)', r'\1\nnew line', f_content)
# return pointer to top of file so we can re-write the content with replaced string
f.seek(0)
# clear file content
f.truncate()
# re-write the content with the updated content
f.write(f_content)
# close file
f.close()
Option 2) Calculez la ligne médiane et remplacez-la par cette ligne plus la ligne supplémentaire.
# open file with r+b (allow write and binary mode)
f = open("file.log" , 'r+b')
# get array of lines
f_content = f.readlines()
# get middle line
middle_line = len(f_content)/2
# overwrite middle line
f_content[middle_line] += "\nnew line"
# return pointer to top of file so we can re-write the content with replaced string
f.seek(0)
# clear file content
f.truncate()
# re-write the content with the updated content
f.write(''.join(f_content))
# close file
f.close()
A écrit une petite classe pour faire ça proprement.
import tempfile
class FileModifierError(Exception):
pass
class FileModifier(object):
def __init__(self, fname):
self.__write_dict = {}
self.__filename = fname
self.__tempfile = tempfile.TemporaryFile()
with open(fname, 'rb') as fp:
for line in fp:
self.__tempfile.write(line)
self.__tempfile.seek(0)
def write(self, s, line_number = 'END'):
if line_number != 'END' and not isinstance(line_number, (int, float)):
raise FileModifierError("Line number %s is not a valid number" % line_number)
try:
self.__write_dict[line_number].append(s)
except KeyError:
self.__write_dict[line_number] = [s]
def writeline(self, s, line_number = 'END'):
self.write('%s\n' % s, line_number)
def writelines(self, s, line_number = 'END'):
for ln in s:
self.writeline(s, line_number)
def __popline(self, index, fp):
try:
ilines = self.__write_dict.pop(index)
for line in ilines:
fp.write(line)
except KeyError:
pass
def close(self):
self.__exit__(None, None, None)
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
with open(self.__filename,'w') as fp:
for index, line in enumerate(self.__tempfile.readlines()):
self.__popline(index, fp)
fp.write(line)
for index in sorted(self.__write_dict):
for line in self.__write_dict[index]:
fp.write(line)
self.__tempfile.close()
Ensuite, vous pouvez l'utiliser de cette façon:
with FileModifier(filename) as fp:
fp.writeline("String 1", 0)
fp.writeline("String 2", 20)
fp.writeline("String 3") # To write at the end of the file
Si vous connaissez unix, vous pouvez essayer ce qui suit:
Notes: $ signifie l'invite de commande
Supposons que vous ayez un fichier my_data.txt avec un contenu en tant que tel:
$ cat my_data.txt
This is a data file
with all of my data in it.
Ensuite, en utilisant le os
module, vous pouvez utiliser les sed
commandes habituelles
import os
# Identifiers used are:
my_data_file = "my_data.txt"
command = "sed -i 's/all/none/' my_data.txt"
# Execute the command
os.system(command)
Si vous n'êtes pas au courant de sed, vérifiez-le, il est extrêmement utile.