Modifica di una riga specifica nel file di testo in Python


88

Diciamo che ho un file di testo contenente:

Dan
Warrior
500
1
0

C'è un modo per modificare una riga specifica in quel file di testo? In questo momento ho questo:

#!/usr/bin/env python
import io

myfile = open('stats.txt', 'r')
dan = myfile.readline()
print dan
print "Your name: " + dan.split('\n')[0]

try:
    myfile = open('stats.txt', 'a')
    myfile.writelines('Mage')[1]
except IOError:
        myfile.close()
finally:
        myfile.close()

Sì, lo so che myfile.writelines('Mage')[1]non è corretto. Ma hai capito il mio punto, giusto? Sto cercando di modificare la riga 2 sostituendo Warrior con Mage. Ma posso anche farlo?


1
Penso che questo post copra quello che stai cercando: stackoverflow.com/questions/1998233/…
Kyle Wild

1
Se devi fare spesso questo genere di cose, potresti voler convertire questo file da testo a qualcosa come bdb o altro bdb-simile.
Nick Bastin

Risposte:


125

Vuoi fare qualcosa del genere:

# with is like your try .. finally block in this case
with open('stats.txt', 'r') as file:
    # read a list of lines into data
    data = file.readlines()

print data
print "Your name: " + data[0]

# now change the 2nd line, note that you have to add a newline
data[1] = 'Mage\n'

# and write everything back
with open('stats.txt', 'w') as file:
    file.writelines( data )

La ragione di ciò è che non puoi fare qualcosa come "cambiare riga 2" direttamente in un file. Puoi solo sovrascrivere (non eliminare) parti di un file: ciò significa che il nuovo contenuto copre solo il vecchio contenuto. Quindi, se hai scritto "Mage" sulla riga 2, la riga risultante sarebbe "Mageior".


2
Ciao Jochen, l'istruzione "with open (filename, mode)" chiude implicitamente anche il nome del file dopo che il programma è uscito, giusto?
Radu

@ Gabriel Thx, questo è importante da notare, anche se ancora non uso l'istruzione with ... as file. Pythonic o no, non mi piace :)
Radu

@Radu, è questione di abituarsi. Ho anche usato per chiudere manualmente i file aperti tramite, close.ma ora vedo che l'uso di un withblocco è molto più pulito.
Gabriel

5
È corretto presumere che questa sia una soluzione preferita per file di piccole dimensioni? Altrimenti potremmo aver bisogno di molta memoria solo per memorizzare i dati. Inoltre, anche per 1 modifica, dobbiamo riscrivere l'intera cosa.
Arindam Roychowdhury,

11
Male .. cosa succede se si dispone di un file da 20 GB?
Brans Ds

21

è possibile utilizzare fileinput per eseguire modifiche sul posto

import fileinput
for  line in fileinput.FileInput("myfile", inplace=1):
    if line .....:
         print line

19
def replace_line(file_name, line_num, text):
    lines = open(file_name, 'r').readlines()
    lines[line_num] = text
    out = open(file_name, 'w')
    out.writelines(lines)
    out.close()

E poi:

replace_line('stats.txt', 0, 'Mage')

9
questo caricherà l'intero contenuto del file in memoria, il che potrebbe non essere una buona cosa se il file è enorme.
Steve Ng

@SteveNg hai una soluzione per il problema che hai notato? sia questa risposta che quella accettata si basano sul caricamento dell'intero file in memoria
Blupon

14

Puoi farlo in due modi, scegli quello che si adatta alle tue esigenze:

Metodo I.) Sostituzione utilizzando il numero di riga. È possibile utilizzare la funzione incorporata enumerate()in questo caso:

Innanzitutto, in modalità di lettura, ottieni tutti i dati in una variabile

with open("your_file.txt",'r') as f:
    get_all=f.readlines()

Secondo, scrivi nel file (dove enumerate entra in azione)

with open("your_file.txt",'w') as f:
    for i,line in enumerate(get_all,1):         ## STARTS THE NUMBERING FROM 1 (by default it begins with 0)    
        if i == 2:                              ## OVERWRITES line:2
            f.writelines("Mage\n")
        else:
            f.writelines(line)

Metodo II.) Utilizzando la parola chiave che si desidera sostituire:

Apri il file in modalità di lettura e copia il contenuto in un elenco

with open("some_file.txt","r") as f:
    newline=[]
    for word in f.readlines():        
        newline.append(word.replace("Warrior","Mage"))  ## Replace the keyword while you copy.  

"Warrior" è stato sostituito da "Mage", quindi scrivi i dati aggiornati nel file:

with open("some_file.txt","w") as f:
    for line in newline:
        f.writelines(line)

Questo è ciò che sarà l' output in entrambi i casi:

Dan                   Dan           
Warrior   ------>     Mage       
500                   500           
1                     1   
0                     0           

3

Se il tuo testo contiene solo una persona:

import re

# creation
with open('pers.txt','wb') as g:
    g.write('Dan \n Warrior \n 500 \r\n 1 \r 0 ')

with open('pers.txt','rb') as h:
    print 'exact content of pers.txt before treatment:\n',repr(h.read())
with open('pers.txt','rU') as h:
    print '\nrU-display of pers.txt before treatment:\n',h.read()


# treatment
def roplo(file_name,what):
    patR = re.compile('^([^\r\n]+[\r\n]+)[^\r\n]+')
    with open(file_name,'rb+') as f:
        ch = f.read()
        f.seek(0)
        f.write(patR.sub('\\1'+what,ch))
roplo('pers.txt','Mage')


# after treatment
with open('pers.txt','rb') as h:
    print '\nexact content of pers.txt after treatment:\n',repr(h.read())
with open('pers.txt','rU') as h:
    print '\nrU-display of pers.txt after treatment:\n',h.read()

Se il tuo testo contiene più persone:

import re

# creation
with open('pers.txt','wb') as g:
    g.write('Dan \n Warrior \n 500 \r\n 1 \r 0 \n Jim  \n  dragonfly\r300\r2\n10\r\nSomo\ncosmonaut\n490\r\n3\r65')

with open('pers.txt','rb') as h:
    print 'exact content of pers.txt before treatment:\n',repr(h.read())
with open('pers.txt','rU') as h:
    print '\nrU-display of pers.txt before treatment:\n',h.read()


# treatment
def ripli(file_name,who,what):
    with open(file_name,'rb+') as f:
        ch = f.read()
        x,y = re.search('^\s*'+who+'\s*[\r\n]+([^\r\n]+)',ch,re.MULTILINE).span(1)
        f.seek(x)
        f.write(what+ch[y:])
ripli('pers.txt','Jim','Wizard')


# after treatment
with open('pers.txt','rb') as h:
    print 'exact content of pers.txt after treatment:\n',repr(h.read())
with open('pers.txt','rU') as h:
    print '\nrU-display of pers.txt after treatment:\n',h.read()

Se il "lavoro" di un individuo fosse di lunghezza costante nel testo, potresti cambiare solo la porzione di testo corrispondente al "lavoro" dell'individuo desiderato: è la stessa idea di quella di mittente.

Ma secondo me sarebbe meglio mettere le caratteristiche degli individui in un dizionario registrato in file con cPickle:

from cPickle import dump, load

with open('cards','wb') as f:
    dump({'Dan':['Warrior',500,1,0],'Jim':['dragonfly',300,2,10],'Somo':['cosmonaut',490,3,65]},f)

with open('cards','rb') as g:
    id_cards = load(g)
print 'id_cards before change==',id_cards

id_cards['Jim'][0] = 'Wizard'

with open('cards','w') as h:
    dump(id_cards,h)

with open('cards') as e:
    id_cards = load(e)
print '\nid_cards after change==',id_cards

2

Questa sera mi sono esercitato a lavorare sui file e ho capito che posso basarmi sulla risposta di Jochen per fornire una maggiore funzionalità per un uso ripetuto / multiplo. Sfortunatamente la mia risposta non affronta il problema della gestione di file di grandi dimensioni, ma semplifica la vita con file più piccoli.

with open('filetochange.txt', 'r+') as foo:
    data = foo.readlines()                  #reads file as list
    pos = int(input("Which position in list to edit? "))-1  #list position to edit
    data.insert(pos, "more foo"+"\n")           #inserts before item to edit
    x = data[pos+1]
    data.remove(x)                      #removes item to edit
    foo.seek(0)                     #seeks beginning of file
    for i in data:
        i.strip()                   #strips "\n" from list items
        foo.write(str(i))

0

Questo è il modo più semplice per farlo.

fin = open("a.txt")
f = open("file.txt", "wt")
for line in fin:
    f.write( line.replace('foo', 'bar') )
fin.close()
f.close()

Spero che funzioni per te.


-1
#read file lines and edit specific item

file=open("pythonmydemo.txt",'r')
a=file.readlines()
print(a[0][6:11])

a[0]=a[0][0:5]+' Ericsson\n'
print(a[0])

file=open("pythonmydemo.txt",'w')
file.writelines(a)
file.close()
print(a)

1
Benvenuto in Stack Overflow! Tieni presente che stai rispondendo a una domanda molto vecchia e già risolta. Ecco una guida su come rispondere .
help-info.de

@ ajay-jaiswal Per favore specifica la tua domanda e fornisci un esempio minimo riproducibile e tutti i messaggi di errore che ricevi. Hai pubblicato il codice ma non la domanda vera e propria.
dmitryro

-2

Supponiamo di avere un file denominato file_namecome segue:

this is python
it is file handling
this is editing of line

Dobbiamo sostituire la riga 2 con "la modifica è completata":

f=open("file_name","r+")
a=f.readlines()
for line in f:
   if line.startswith("rai"):
      p=a.index(line)
#so now we have the position of the line which to be modified
a[p]="modification is done"
f.seek(0)
f.truncate() #ersing all data from the file
f.close()
#so now we have an empty file and we will write the modified content now in the file
o=open("file_name","w")
for i in a:
   o.write(i)
o.close()
#now the modification is done in the file
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.