Schreiben in eine neue Datei, falls nicht vorhanden, und Anhängen an eine Datei, falls vorhanden

73

Ich habe ein Programm, das einen Benutzer highscorein eine Textdatei schreibt . Die Datei wird vom Benutzer benannt, wenn er a auswählt playername.

Wenn die Datei mit diesem bestimmten Benutzernamen bereits vorhanden ist, sollte das Programm an die Datei angehängt werden (damit Sie mehr als eine sehen können highscore). Wenn eine Datei mit diesem Benutzernamen nicht vorhanden ist (z. B. wenn der Benutzer neu ist), sollte eine neue Datei erstellt und in diese geschrieben werden.

Hier ist der relevante, bisher nicht funktionierende Code:

try: 
    with open(player): #player is the varible storing the username input
        with open(player, 'a') as highscore:
            highscore.write("Username:", player)

except IOError:
    with open(player + ".txt", 'w') as highscore:
        highscore.write("Username:", player)

Der obige Code erstellt eine neue Datei, falls diese nicht vorhanden ist, und schreibt in sie. Wenn es existiert, wurde beim Überprüfen der Datei nichts angehängt, und es werden keine Fehler angezeigt.

Bondenn
quelle
Was ist der Zweck der ersten with open(player):Aussage? Außerdem erstellen Sie in Ihrem Ausnahmebehandler eine andere Datei player + '.txt'als die, in die Sie ursprünglich schreiben wollten.
Markku K.
@ MarkkuK Ich habe das einer anderen Frage bei stackoverflow entnommen, bei der Sie überprüfen, ob eine Datei vorhanden ist. Also der mit open (player): prüft ob die Datei existiert, zumindest dachte ich mir das. Okey, ich verstehe, dachte nur, ich müsste die ".txt" verwenden, damit die Datei eine Textdatei ist.
Bondenn
1
In jedem Fall können Sie einfach verwenden open(whatever,'a') as highscore:, und es wird tun, was Sie wollen: Erstellen Sie die Datei, wenn sie nicht vorhanden ist, oder hängen Sie sie an, wenn sie vorhanden ist
Markku K.
@ MarkkuK Meine Güte, du hast Recht, ich muss Python lieben, weil es einfach ist. Vielen Dank!
Bondenn

Antworten:

50

Mir ist nicht klar, wo genau der Highscore gespeichert ist, an dem Sie interessiert sind, aber der folgende Code sollte genau das sein, was Sie benötigen, um zu überprüfen, ob die Datei vorhanden ist, und um sie gegebenenfalls anzufügen. Ich ziehe diese Methode dem "try / Except" vor.

import os
player = 'bob'

filename = player+'.txt'

if os.path.exists(filename):
    append_write = 'a' # append if already exists
else:
    append_write = 'w' # make a new file if not

highscore = open(filename,append_write)
highscore.write("Username: " + player + '\n')
highscore.close()
qmorgan
quelle
11
Ist das nicht anfällig für eine Rennbedingung?
user541686
22
warum nicht einfach mit dem Modus "a +" öffnen?
Eric des Courtis
26
Was ist, wenn wir nur verwenden open(filename, 'a'), es erstellt auch die Datei, wenn nicht vorhanden, und anhängen, wenn vorhanden.
Abolfazl
@EricdesCourtis "a" und "a +" lassen Sie nicht nach beliebigen Offsets suchen (nur bis zum Ende der Datei).
Naktinis
1
Ich ziehe diese Methode dem "try / Except" vor. Ist die persönliche Präferenz wichtiger als die Tatsache, dass der EAFP- Stil in Python allgemein als besser angesehen wird?
AMC
81

Haben Sie den Modus 'a +' ausprobiert?

with open(filename, 'a+') as f:
    f.write(...)

Beachten Sie jedoch, dass f.tell()in Python 2.x 0 zurückgegeben wird. Siehe https://bugs.python.org/issue22651 Informationen finden .

Eric des Courtis
quelle
1
Upvote, obwohl Sie diesem Vorschlag "wenn Sie sich nicht mit dem von f.tell()" gemeldeten Wert befassen "voranstellen müssen .
personal_cloud
1
Ich bin besorgt über die Portabilität von a+aus diesem Grund in den Dokumenten : on some Unix systems means that all writes append to the end of the file regardless of the current seek position.
Jarrod Smith
@ JarrodSmith Keine wirkliche Sorge IMO. Aus Dokumenten: 'a' for appending (which on some Unix systems means that all writes append to the end of the file regardless of the current seek position).Ich denke, dies ist für die meisten Verwendungen von Dateien in Ordnung (zum Beispiel immer anhängen). Wenn Sie nach bestimmten Offsets suchen müssen, werden Sie Dateien wahrscheinlich sowieso nicht auf diese Weise öffnen.
Eric des Courtis
1
Ich habe beide aund a+auf Mac OS High Sierra unter Python 2.7.15 ausprobiert und beide an das Ende der Datei angehängt und in beiden f.tell()das gleiche gemeldet (nicht 0). Der verknüpfte Fehler hat auch einige tragbare Problemumgehungen, z. B. setzen Sie die Suchposition manuell auf das Ende der Datei oder verwenden Sie iostattdessen das Modul, das diesen Fehler nicht aufweist.
Davos
Warum, a+wenn du nur kannst a?
Mateen Ulhaq
22

Öffnen Sie es einfach im 'a'Modus:

a   Zum Schreiben offen. Die Datei wird erstellt, wenn sie nicht vorhanden ist. Der Stream befindet sich am Ende der Datei.

with open(filename, 'a') as f:
    f.write(...)

Überprüfen Sie die Stream-Position, um festzustellen, ob Sie in eine neue Datei schreiben. Wenn es Null ist, war entweder die Datei leer oder es handelt sich um eine neue Datei.

with open('somefile.txt', 'a') as f:
    if f.tell() == 0:
        print('a new file or the file was empty')
        f.write('The header\n')
    else:
        print('file existed, appending')
    f.write('Some data\n')

Wenn Sie immer noch Python 2 verwenden, um den Fehler zu umgehen , fügen Sie entweder f.seek(0, os.SEEK_END)direkt danach hinzu openoder verwenden Sie io.openstattdessen.

Nutzer
quelle
2

Beachten Sie, dass der gleiche Fehler angezeigt wird, wenn der übergeordnete Ordner der Datei nicht vorhanden ist:

IOError: [Errno 2] Keine solche Datei oder kein solches Verzeichnis:

Unten ist eine andere Lösung, die diesen Fall behandelt:
(*) Ich habe verwendet sys.stdoutund printanstatt f.writenur einen anderen Anwendungsfall zu zeigen

# Make sure the file's folder exist - Create folder if doesn't exist
folder_path = 'path/to/'+folder_name+'/'
if not os.path.exists(folder_path):
     os.makedirs(folder_path)

print_to_log_file(folder_path, "Some File" ,"Some Content")

Wo sich der Interne print_to_log_filenur um die Dateiebene kümmert:

# If you're not familiar with sys.stdout - just ignore it below (just a use case example)
def print_to_log_file(folder_path ,file_name ,content_to_write):

   #1) Save a reference to the original standard output       
    original_stdout = sys.stdout   
    
    #2) Choose the mode
    write_append_mode = 'a' #Append mode
    file_path = folder_path + file_name
    if (if not os.path.exists(file_path) ):
       write_append_mode = 'w' # Write mode
     
    #3) Perform action on file
    with open(file_path, write_append_mode) as f:
        sys.stdout = f  # Change the standard output to the file we created.
        print(file_path, content_to_write)
        sys.stdout = original_stdout  # Reset the standard output to its original value

Betrachten Sie die folgenden Zustände:

'w'  --> Write to existing file
'w+' --> Write to file, Create it if doesn't exist
'a'  --> Append to file
'a+' --> Append to file, Create it if doesn't exist

In Ihrem Fall würde ich einen anderen Ansatz verwenden und nur 'a'und verwenden 'a+'.

RtmY
quelle
0

Verwenden des pathlibModuls ( objektorientierte Dateisystempfade von Python )

Nur zum Spaß ist dies vielleicht die neueste pythonische Version der Lösung.

from pathlib import Path 

path = Path(f'{player}.txt')
path.touch()  # default exists_ok=True
with path.open('a') as highscore:
   highscore.write(f'Username:{player}')
ohailolcat
quelle