Je voudrais insérer une chaîne à une colonne spécifique d'une ligne spécifique dans un fichier.
Supposons que j'ai un fichier file.txt
How was the English test?
How was the Math test?
How was the Chemistry test?
How was the test?
Je voudrais changer la dernière ligne pour dire How was the History test?
en ajoutant la chaîne History
à la ligne 4, colonne 13.
Actuellement, je lis dans chaque ligne du fichier et ajoute la chaîne à la position spécifiée.
with open("file.txt", "r+") as f:
# Read entire file
lines = f.readlines()
# Update line
lino = 4 - 1
colno = 13 -1
lines[lino] = lines[lino][:colno] + "History " + lines[lino][colno:]
# Rewrite file
f.seek(0)
for line in lines:
f.write(line)
f.truncate()
f.close()
Mais j'estime que je devrais pouvoir simplement ajouter la ligne au fichier sans avoir à lire et réécrire le fichier entier .
Ceci est peut-être une copie de ce qui suit SO thread
Le moyen le plus rapide de supprimer une ligne d'un fichier volumineux en Python
En haut, il est question de suppression, qui est simplement une manipulation, et la vôtre est plutôt une modification. Donc, le code serait mis à jour comme ci-dessous
def update(filename, lineno, column, text):
fro = open(filename, "rb")
current_line = 0
while current_line < lineno - 1:
fro.readline()
current_line += 1
seekpoint = fro.tell()
frw = open(filename, "r+b")
frw.seek(seekpoint, 0)
# read the line we want to update
line = fro.readline()
chars = line[0: column-1] + text + line[column-1:]
while chars:
frw.writelines(chars)
chars = fro.readline()
fro.close()
frw.truncate()
frw.close()
if __== "__main__":
update("file.txt", 4, 13, "History ")
Dans un fichier volumineux, il est logique de ne pas modifier le fichier avant la mise à jour. Imaginez que vous ayez un fichier avec des lignes de 10 Ko et que la mise à jour ait lieu à 9 Ko. Votre code chargera toutes les lignes de données 9K
en mémoire inutilement. Le code que vous avez fonctionne encore mais ce n’est pas la meilleure façon de le faire
Cette réponse ne fera que parcourir le fichier une seule fois et tout écrire après l'insertion. Dans les cas où l'insertion est à la fin, il n'y a presque pas de temps système et où l'insertion au début n'est pas pire qu'une lecture et une écriture complètes.
def insert(file, line, column, text):
ln, cn = line - 1, column - 1 # offset from human index to Python index
count = 0 # initial count of characters
with open(file, 'r+') as f: # open file for reading an writing
for idx, line in enumerate(f): # for all line in the file
if idx < ln: # before the given line
count += len(line) # read and count characters
Elif idx == ln: # once at the line
f.seek(count + cn) # place cursor at the correct character location
remainder = f.read() # store all character afterwards
f.seek(count + cn) # move cursor back to the correct character location
f.write(text + remainder) # insert text and rewrite the remainder
return # You're finished!
La fonction readlines()
lit l'intégralité du fichier. Mais ce n'est pas obligé. Il lit en fait de la position du curseur du fichier actuel jusqu'à la fin, qui se trouve être 0
juste après son ouverture. (Pour confirmer cela, essayez f.tell()
juste après la déclaration with
.) Et si nous commencions plus près de la fin du fichier?
La manière dont votre code est écrit implique une connaissance préalable du contenu et de la présentation de votre fichier. Pouvez-vous placer des contraintes sur chaque ligne? Par exemple, compte tenu de vos exemples de données, nous pourrions dire que les lignes ont une longueur garantie de 27 octets ou moins. Arrondissons cela à 32 pour "puissance de 2-ness" et essayons de chercher en arrière à la fin du fichier.
# note the "rb+"; need to open in binary mode, else seeking is strictly
# a "forward from 0" operation. We need to be able to seek backwards
with open("file.txt", "rb+") as f:
# caveat: if file is less than 32 bytes, this will throw
# an exception. The second parameter, 2, says "from end of file"
f.seek(-32, 2)
last = f.readlines()[-1].decode()
A ce stade, le code n'a lu que les 32 derniers octets du fichier.1 readlines()
(au niveau de l'octet) recherchera l'octet de fin de ligne (sous Unix, \n
ou 0x0a
ou la valeur d'octet 10) et renverra l'avant et l'après. Énoncée:
>>> last = f.readlines()
>>> print( last )
[b'hemistry test?\n', b'How was the test?']
>>> last = last[-1]
>>> print( last )
b'How was the test?'
De manière cruciale, cela fonctionne de manière robuste sous le codage UTF-8 en exploitant la propriété UTF-8 que les valeurs d'octet ASCII sous 128 do not / se produisent lors du codage d'octets non ASCII. En d'autres termes, l'octet exact \n
(ou 0x0a
) apparaît uniquement en tant que nouvelle ligne et jamais en tant que partie d'un caractère. Si vous utilisez un codage non UTF-8, vous devrez vérifier si les hypothèses de code sont toujours valables.
Autre remarque: 32 octets sont arbitraires compte tenu des données d'exemple. Une valeur plus réaliste et typique pourrait être 512, 1024 ou 4096. Enfin, pour revenir à un exemple de travail pour vous:
with open("file.txt", "rb+") as f:
# caveat: if file is less than 32 bytes, this will throw
# an exception. The second parameter, 2, says "from end of file"
f.seek(-32, 2)
# does *not* read while file, unless file is exactly 32 bytes.
last = f.readlines()[-1]
last_decoded = last.decode()
# Update line
colno = 13 -1
last_decoded = last_decoded[:colno] + "History " + last_decoded[colno:]
last_line_bytes = len( last )
f.seek(-last_line_bytes, 2)
f.write( last_decoded.encode() )
f.truncate()
Notez qu'il n'y a pas besoin de f.close()
. L'instruction with
le gère automatiquement.
1 Le pédant remarquera correctement que l'ordinateur et le système d'exploitation ont probablement lu au moins 512 octets, sinon 4 096 octets, relatifs à la taille de la page sur disque ou en mémoire.
Vous pouvez utiliser ce morceau de code:
with open("test.txt",'r+') as f:
# Read the file
lines=f.readlines()
# Gets the column
column=int(input("Column:"))-1
# Gets the line
line=int(input("Line:"))-1
# Gets the Word
Word=input("Word:")
lines[line]=lines[line][0:column]+Word+lines[line][column:]
# Delete the file
f.seek(0)
for i in lines:
# Append the lines
f.write(i)
Je ne sais pas si vous avez eu des problèmes pour modifier votre fichier afin qu'il contienne le mot "Historique", ou si vous vouliez savoir comment réécrire uniquement certaines parties d'un fichier, sans avoir à réécrire le tout.
Si vous aviez des problèmes en général, voici un code simple qui devrait fonctionner, tant que vous connaissez la ligne du fichier que vous souhaitez modifier. Il suffit de changer les première et dernière lignes du programme pour lire et écrire les instructions en conséquence.
fileData="""How was the English test?
How was the Math test?
How was the Chemistry test?
How was the test?""" # So that I don't have to create the file, I'm writing the text directly into a variable.
fileData=fileData.split("\n")
fileData[3]=fileData[3][:11]+" History"+fileData[3][11:] # The 3 referes to the line to add "History" to. (The first line is line 0)
storeData=""
for i in fileData:storeData+=i+"\n"
storeData=storeData[:-1]
print(storeData) # You can change this to a write command.
Si vous vouliez savoir comment changer des "parties" spécifiques dans un fichier, sans avoir à tout réécrire, alors (à ma connaissance) ce n'est pas possible.
Supposons que vous ayez un fichier avec Ths is a TEST file.
et que vous vouliez le corriger pour dire This is a TEST file.
; vous seriez techniquement en train de changer 17 caractères et d’en ajouter un à la fin. Vous changez le "s" en un "i", le premier espace en un "s", le "i" (de "est") en un espace, etc ... lorsque vous décalez le texte.
Un ordinateur ne peut pas réellement insérer des octets entre d'autres octets. Il ne peut que déplacer les données, pour faire de la place.