文件读写

文件处理是很常见的IO操作。通常我们使用 input 从控制台读取输入,然后将用户输入的内容输出到控制台。使用文件操作,我们就可以将用户的输入写入文件,或者将不同数据源中的数据移植到文件中。Python为创建文件、读取文件、更新文件、和删除文件都提供了相对应的函数。

操作文件最核心的函数是open()函数,此函数需要两个参数:filename, mode。filename对应你要操作的文件名,mode对应你要对文件进行的操作,以下是不同mode对应的具体意义:

“r”读模式默认操作。打开文件, 并读取其内容, 如果文件不存在就会返回错误。
“a”追加模式添加内容,如果文件不存在,会自动创建其文件。
“w”写模式打开文件,并写入内容,如果文件不存在,就会自动创建。
“x”创模式创建特定的文件,如果文件已存在,就会返回错误。

此外,你还可以定义是要以什么形式来处理文件:

“t”文本文本模式 (默认)
“b”二进制二进制模式(比如图片)

打开文件

假设我们创建了文件file.txt,此文件和Python文件位于相同的文件夹:

Hello! Welcome to file.txt
This file is for testing purposes.
Good Luck!

若要打开文件,我们直接使用open()函数,并返回一个文件实例,此实例有一个read()方法供我们使用,可以读取文件的内容:

f = open("file.txt")
print(f.read())

以下代码实现了相同的功能,”r”代表读模式,”t”代表文本模式,他们都是默认值,你不需要定义他们。(注意:要保证文件存在,不然读模式会返回错误)

f = open("file.txt", "rt")
print(f.read())

读取文件

读取文件的方式有很多种,read()函数默认情况下会读取整个文件,如果我们只想读取特定字符数,可以给read添加参数来限定字符数。如果想要逐行读取文件,可以使用readline()函数。

f = open("file.txt", "r")
print(f.read(5)) # Return the first 5 characters of the file
print(f.readline()) # Read one line of the file 
print(f.readline()) # Read the second line

如果迭代文件,文件也会一行一行地被读取:

f = open("file.txt", "r")
for x in f:
    print(x)

每次操作完文件后,需要使用close()函数,将文件关闭:

f = open("file.txt", "r")
print(f.readline())
f.close()

写和创建文件

如果想将内容写入文件,我们必须在open()函数中添加”a”或”w”参数。”a”是追加模式,会在文件已存内容后面添加新内容。”w”是写模式,新内容会被旧内容覆盖。

f = open("file.txt", "a")
f.write("Now the file has more content!") # append the content to the file
f.close()

# open and read the file after the appending:
f = open("file.txt", "r")
print(f.read())
f.close()
f = open("file.txt", "w")
f.write("Woops! I have deleted the content!") # overwrite the content
f.close()

# open and read the file after the appending:
f = open("file.txt", "r")
print(f.read())

如果想要创建一个文件,在open函数中使用参数”x”, “a”或”w”都可以。”x”能创建一个文件,但是如果文件已存在,就会返回错误。如果指定的文件不存在,”a”和”w”模式都会自动创建一个新文件。

f = open("file2.txt", "x") # a new empty file is created.
f = open("file3.txt", "w") # create a new file if it does not exist

删除文件

如果要删除一个文件,我们需要调用os模块,然后使用os.remove()函数:

import os
os.remove("file.txt")

为了避免出现错误,在删除一个文件前最好检查一下此文件是否存在:

import os
if os.path.exists("file.txt"):
    os.remove("file.txt")
else:
    print("The file does not exist")

如果要删除整个文件夹,使用os.rmdir()函数即可:

import os
os.rmdir("newfolder")

异常处理

有时候我们的程序会出现异常,但我们又不想这些代码影响到软件的正常运行,这时候我们就要使用Python中的try,来处理有可能出现的异常:

try:
    print(x)
except:
    print("An exception occurred")

上面代码中因为x没有定义,所以会出现错误,当错误出现时,except中的代码就会被运行。如果不使用try,程序就会崩溃,并出现错误。

如果我们希望对特定的异常进行特定的处理,我们可以使用多个except语句:

try:
    print(x)
except NameError:
    print("Variable x is not defined")
except:
    print("Something else went wrong")

除了NameError之外的异常出现的话,最后的except会被运行。如果想对无异常的情况进行特定处理,我们可以使用else关键词:

try:
    print("Hello")
except:
    print("Something went wrong")
else:
    print("Nothing went wrong")

Python也提供了很方便的finally,定义finally代码块后,不管try中的代码会不会引起异常,finally中的代码都会被执行:

try:
    print(x)
except:
    print("Something went wrong")
finally:
    print("The 'try except' is finished")

在处理文件的时候,我们经常会在finally中关闭文件,来保证程序的正常运行:

f = open("file.txt")
try: 
    f.write("Awesome")
except:
    print("Something went wrong when writing to the file")
finally:
    f.close()

with语句

with语句适合用于对资源进行访问的场合,确保运行过程中不管是否有异常,都会执行必要的“清理”操作,释放被操作的资源,比如文件的自动关闭或者线程中锁的自动获取和释放等。

在我们处理文件时,通常要编写以下的代码来保证程序正常运行:

try:
    file = open("file.txt")
    content = file.read()
except:
    print("Error")
finally:
    file.close()

虽然以上代码运行正常,可是比较冗长。使用with的话,不仅使代码更加简洁,还能处理上下文环境产生的异常:

with open("file.txt", "w") as file:
    file.write("Hi there!")

with的工作原理我这里不展开讲,简单来说,紧跟在with后面的语句被求值后,返回对象内置的__enter__()函数会被调用,这个方法的返回值会被赋值给as后面的变量。当with后面的代码全部被执行完之后,将会调用返回对象的__exit__()方法。

实际上,在with后面的代码抛出异常后,__exit__()函数会被执行。一般清理资源,关闭文件等操作,都会被放在exit()方法中。总之,with…as表达式简化了每次都要写finally的繁琐工作,极大提升了代码的优雅性。我们甚至还能在with后面使用多项as:

with open("file.txt") as f1, open("file2.txt") as f2:
    # do anything

实践练习

请创建一个程序可以根据用户的输入对文件进行读或者写操作,不管读还是写,都需要用户先手动输入文件名。在读操作中,如果文件读取成功,需要打印文件内容。在写操作中,使用追写模式添加任意内容后,打印修改后的文件内容即可。(注意:要对可能出现的异常进行处理,并在最后将文件关闭)

def file_operator(file_name, mode):
    try:
        if mode == "r":
            with open(file_name, "r") as file:
                print(file.read())
        elif mode == "w":
            with open(file_name, "a") as file:
                file.write("New Content")
                file.close()
                file = open(file_name, "r")
                print(file.read())
    except IOError:
        print("Error")

def prompt():
    message = "Please input the file name: "
    file_name = input(message)
    message = "Read or Write?(r, w) "
    mode = input(message)
    file_operator(file_name, mode)
    
prompt()