如果文件不存在则写入新文件,如果文件存在则追加到文件中。

139

我有一个程序,它将用户的highscore写入文本文件。当用户选择playername时,文件将以该用户名命名。

如果具有该特定用户名的文件已经存在,则程序应将数据追加到文件中(以便您可以查看多个highscore)。如果不存在具有该用户名的文件(例如,如果用户是新用户),则应创建一个新文件并将数据写入其中。

以下是相关的但迄今为止不起作用的代码:

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)

上面的代码会在文件不存在时创建新文件并写入内容。如果文件已存在,在检查该文件时没有追加任何内容,也不会出现错误。


第一个 with open(player): 语句的目的是什么?此外,在您的异常处理程序中,您正在创建一个不同的文件 player + '.txt',而不是您原本想要写入的文件。 - Markku K.
@MarkkuK 我从stackoverflow的另一个问题中获取了这个代码,用于检查文件是否存在。因此,使用with open(player)可以检查文件是否存在,至少我是这么认为的。好的,我明白了,只是以为必须使用“.txt”才能使文件成为文本文件。 - Bondenn
2
无论如何,您只需使用 open(whatever,'a') as highscore:,它将实现您想要的功能:如果文件不存在,则创建该文件,如果文件存在,则将内容追加到文件中。 - Markku K.
@MarkkuK 哇,你说得对,Python 的简洁之美真是让人爱不释手。谢谢! - Bondenn
5个回答

164

你尝试过模式'a+'吗?

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

需要注意的是,在Python 2.x中,f.tell()将返回0。有关详细信息,请参见https://bugs.python.org/issue22651


2
点赞,不过需要在建议前加上“如果您不关心f.tell()报告的值”。 - personal_cloud
1
我对a+的可移植性存在担忧,因为在文档中有这样的描述:在某些Unix系统上,不考虑当前的寻址位置,所有写入的数据都会被追加到文件末尾 - Jarrod Smith
@JarrodSmith 在我看来不是一个真正的问题。从文档中可以看出:'a'表示追加(在某些Unix系统上,这意味着所有写入都会追加到文件的末尾,而不管当前的寻址位置)。 我认为对于大多数文件的使用(例如始终追加),这是可以接受的。如果您需要在特定偏移处进行寻址,则通常不会以这种方式打开文件。 - Eric des Courtis
1
我在 Mac OS High Sierra 上尝试了 Python 2.7.15 的 aa+ 两种模式,它们都会将内容附加到文件末尾,并且 f.tell() 在两种模式下都报告相同的值(不是0)。该链接中提供了一些便携的解决方法,例如手动设置文件指针位置到文件末尾,或者改用没有此 bug 的 io 模块。 - Davos
1
为什么使用 a+,而不是直接使用 a 呢? - Mateen Ulhaq
2
这是最正确的。如果文件不存在,'a+' 将创建它,而 'a' 将因为找不到文件而失败(在 Raspian 上使用 Python 3.7)。 - tomwhipple

67

对我来说不太清楚你感兴趣的高分数具体存储在哪里,但是以下代码应该是你需要检查文件是否存在并在需要时进行附加的代码。与"try/except"相比,我更喜欢这种方法。

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()

16
这不容易出现竞态条件吗? - user541686
31
为什么不用"a+"模式打开它? - Eric des Courtis
37
如果我们只使用open(filename, 'a'),它会在文件不存在时创建文件,并在文件存在时进行追加操作。 - Abolfazl
2
我更喜欢这种方法,而不是“try/except”。个人偏好比EAFP风格在Python中通常被认为更好的事实更重要吗? - AMC
1
@jdhao 在 Python 3 中可能是正确的,但当问题被提出时,Python 2 是非常普遍的。 - Chris H
显示剩余3条评论

55

只需在 'a' 模式下打开文件:

a   以写入模式打开。如果文件不存在,则创建该文件。流被定位在文件的末尾。

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

要确定是否在写入新文件,请检查流的位置。如果位置为零,那么要么这个文件是空的,要么就是一个新文件。

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')

如果您仍在使用Python 2,为了解决该缺陷,请在open之后添加f.seek(0, os.SEEK_END)或使用io.open代替。


3
注意,如果文件的父文件夹不存在,你将会得到同样的错误:
IOError: [Errno 2] No such file or directory:
下面是另一个可以处理这种情况的解决方案:
(*) 我使用了sys.stdout和print而不是f.write只是为了展示另一种用法。
# 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")

内部的print_to_log_file仅处理文件级别:

# 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

考虑以下状态:
'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

在你的情况下,我会采用不同的方法,只使用 'a''a+'

0

使用 pathlib 模块(Python 的面向对象文件系统路径

仅供娱乐,这可能是最新的 Pythonic 版本的解决方案。

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}')

1
相比其他答案,这个答案干净而且相对较新。@ohailolcat - 它更符合Python的特点,具体是什么呢?虽然这也是Pythonic的,但它确实需要导入一个新模块。为什么不只用'a+'呢? - JayRugMan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接