【Python基础】06 文件

  在之前的程序中,程序的数据规模都比较小,因此可以直接运行到内存中,但当程序结束或退出时,这些程序数据也会消失。如果程序数据规模较大,或者需要在程序结束前将数据保存在外部设备中,则可以使用外部文件作为程序的输入或输出,从而让数据能够持久存储。下面将介绍在python中常用的文件的操作。

更新历史:

  • 2021年06月27日完成初稿

1. 文件基本概念

  熟悉Windows系统的读者会对系统中的文件和文件夹有熟悉的了解,文件就是存储在某种介质上的信息集合,通过文件名进行标识,按照文件内容的表现形式来看,文件可以分为:二进制文件和文本文件。

 大多数计算机系统都适用ASCII编码通过用唯一的单字节大小的整数值来表示每个字符,文本文件则是以字节序列的方式存储的,每个字节都有一个整数值,从而对应于某些字符。比如字节0x30的整数值为48,表示字符’0’,字节0x61的整数值为97,表示字符’a’等,像这样只由ASCII字符构成的文件称为文本文件,所有的其他文件称为二进制文件。

Unicode编码
  ASCII(American Standard Code for Information Interchange),是英文字符的加密标准,对于汉语、日语等非英文字符则无法表示,因此提出了很多针对于这些特殊字符的文字编码标准,最后Unicode 联合会(Unicode Consortium)修订了最全面且广泛接受的文字编码标准以支持广泛的语言种类,相比于ASCII字符用单字节进行编码,Unicode的基本编码则使用4字节(32bits),不过为节约字节,也提出了Unicode的可变长度字符编码UTF-8和UTF-16等,常见的字符只需要1个或2个字节,而不太常用的字符需要多一些的字节数。

  文件这一概念十分强大,事实上在python中,它将计算机中的各种设备(如括磁盘、键盘、显示器等)抽象为文件对象进行处理,因此程序可以将所有各式各样的设备看成文件,而不需要了解这些设备的具体实现技术。对于程序而言,在处理任何一个文件时(无论是实际意义上的还是逻辑上的),一般有以下几个步骤:

  • 文件打开
  • 文件读、写操作
  • 文件关闭

  下面就介绍则三种具体的文件操作细节。

2. 文件打开与关闭

  在处理文件前,需要打开文件,打开文件时会建立一个文件对象与该文件进行关联,这个文件对象则具有很多属性和方法,通过对该文件对象进行操作来执行对文件的操作。打开文件之后,经过一系列的文件读写操作之后,需要关闭文件以取消文件对象与文件之间的关联。

2.1 打开文件

  打开文件需要利用open()函数,其语法格式如下(省略了不太常用的参数):

扫描二维码关注公众号,回复: 14695851 查看本文章

     open(file, mode=“r”, buffering=-1, encoding=None)

  其中file为文件名,表示当前工作目录下的file文件,若file文件在其他目录下,则需要指出文件路径。mode参数是可选参数,表示文件的操作方式(默认为"r",表示只读模式),buffering参数也是可选参数,表示文件的缓冲模式。而encoding参数是表示文件编码/解码方式的可选参数,由于文本文件采用统一的编码(ASCII或Unicode),因此只针对文本文件模式才可使用,如file文件使用utf-8编码,encoding参数的值应为"utf-8"。该函数的返回值为一个文件对象,它是文件对象的引用,对文件的操作都通过该文件对象进行。

文件路径
  文件路径可以使用绝对路径和相对路径,初学者可以直接使用完整的绝对路径。比如在桌面有一个文本文件text.txt,在Windows系统下,其绝对路径的格式为D:\Documents\Desktop\text.txt,但由于字符’\'是转义字符,因此文件绝对路径应该为"D:\\Documents\\Desktop\\text.txt"("\\“表示字符”\")或者r"D:\Documents\Desktop\text.txt"(r声明之后的字符串是原始字符串)

  打开文件中最重要的参数是mode参数,它会指明打开文件的类型(文本文件还是二进制文件)还有可以对文件的操作,下面列出关于mode参数的可选组合:

mode 功能 说明
基本模式
r 以只读模式打开(默认) 文件必须存在
w 以写模式打开 若文件不存在,则新建文件;若文件存在则清空文件内容
x 创建文件并以写模式打开 若文件已存在则失败
a 以追加模式打开 若文件存在,则向文件的结尾追加内容;若文件不存在则新建文件
t 文本文件模式(默认) 可添加到其他模式中使用(一般可不写)
b 二进制文件模式 可添加到其他模式中使用
+ 读/写模式 可添加到其他模式中使用
常用组合
r+ 以读写模式打开 文件必须存在,读写从文件头部开始
w+ 以读写模式打开 若文件不存在,则新建文件;若文件存在则清空文件内容,之后进行读写操作
a+ 以读和追加模式打开 若文件存在,则向文件的结尾追加内容;若文件不存在则新建文件
rb 以二进制读模式打开
rb+ 以二进制读写模式打开(参见r+)

  根据前述,在python中的各类设备也被抽象成文件,当程序开始运行时,python会自动为该程序打开三个标准文件:

  • 标准输入:对应于键盘设备,文件对象为stdin
  • 标准输出:对应于显示器设备,文件对象为stdout
  • 标准错误:对应于显示器设备,文件对象为stderr

  这三个文件是自动打开的,在之前介绍的input()函数就是将提示文字写入到标准输出stdout中,从而显示在显示屏上。

2.2 关闭文件

  文件打开之后就需要关闭,文件的关闭是通过close()函数执行的,如下所示:

# 文件的打开与关闭
fp = open(r"D:\Documents\Desktop\text.txt", "r+")   # 以读写模式打开位于D:\Documents\Desktop的text.txt文件
# read and write
fp.close()                                        # 关闭文件

  打开文件text.txt时,创建了文件对象fp,之后便可以通过文件对象fp执行文件text.txt的读写操作,最后通过fp.close()来切断文件对象fp与文件text.txt的关联。尽管在程序结束时,程序会检查程序中是否有未关闭的文件而自动关闭未关闭的文件,但还是建议显式地使用close()关闭这些文件,主要原因有以下几点:

  • 同时打开的文件数量是有限的,有必要关闭那些不再使用的文件
  • 文本文件使用缓冲区进行处理(二进制文件可以选择是否使用缓冲区),当对文件进行写入操作时会先将内容写入缓冲区,直至缓冲区写满之后才写入文件中。如果不按时关闭文件,则可能会有一些内容在缓冲区中而未写入文件,当系统发生异常时很可能导致内容无法写入文件从而发生丢失。

3. 文件基本操作

  对于文件而言,除了文件的打开和关闭,最重要的文件操作就是读写文件,不过读写文件需要遵循打开文件时设置的文件模式规则。

3.1 文件的读写操作

  在创建文件对象(设为fp)之后,该对象有需要方法可以使用,如read()、readline()、readlines()、write()、writelines(),下面一一进行介绍(假设文件对象fp允许读写):

读写方法 功能
fp.read(size = -1) 从文件当前位置读取size字节(字符)并返回一个字符串,若size为负数(默认为-1)则读取到文件结束
fp.readline(size = -1) 读取一行中的size字节(字符)并返回一个字符串,默认情况下或size大于本行字符数时,表示读取整行
fp.readlines(hint = -1) 读取文件的多行,并返回一个字符串列表,hint参数可以控制读取行数(初学时使用默认值即可)
fp.write(text) 将text写入文件中并返回写入的字符/字节数
fp.writelines(lines) 向文件中写入列表数据,lines为列表(若需换行,则可在列表元素中加入换行符)

  上面的读写操作中,对于文本文件则以字符为单位,而对于二进制文件则是以字节为单位。下面就是文件的读写操作程序示例,假设我们在桌面一个空白文件text.txt,该文件路径为D:\Documents\Desktop\text.txt,现在我们打开该文件,并在文件中写入两行数据Hello, World!和Hello, Python!:

# 文件的读写
content = ["Hello, World!\n", "Hello, Python!"]     # 写入的内容,用'\n'表示换行
fp = open(r"D:\Documents\Desktop\text.txt", 'w')    # 以写模式打开文件
fp.writelines(content)								# 写入多行
fp.close()

fp = open(r"D:\Documents\Desktop\text.txt", 'r')    # 以读模式打开文件
print(fp.read())
fp.close()
Hello, World!
Hello, Python!

3.2 文件指针

  对于上面的例子,修改一下程序,同时以读写模式打开文件text.txt(初始为空):

# 以读写模式完成文件的读写
content = ["Hello, World!\n", "Hello, Python!"]     # 写入的内容
fp = open(r"D:\Documents\Desktop\text.txt", 'r+')   # 以读写模式打开文件
fp.writelines(content)								# 写入多行
print(fp.read())
fp.close()

  运行程序发现,并没有输出任何内容,原因在于读写操作使用了文件指针。通俗地理解,可以将文件指针理解成一个会移动的游标,当打开文件默认该游标指向文件开始位置,当写入内容后,游标始终指向文件尾部,此时执行文件读操作时则从该位置读入,从而并没有读取到任何内容,而关闭文件再打开文件之后,文件指针指向文件开始位置。

  在python中,提供了一些方法可以返回文件指针位置和移动文件指针位置。Python中提供tell()方法返回当前文件的读写位置,对于文件对象fp而言,使用fp.tell()方法可以返回一个整数,这个整数是离文件起始位置的偏移值。而利用fp.seek(offset, whence = 0)方法可以移动当前读写位置并返回移动后的位置,其中offset是偏移值,whence参数表示指示的位置,一般有以下几个值:

  • whence = 0:相对于文件开始位置,此时offset非负
  • whence = 1:相对于当前文件读写位置,此时offset可正可负
  • whence = 2:相对于文件尾,此时offset为负数或0

  下面通过移动文件指针来实现以读写模式完成文件的读写:

# 文件读写位置的移动
content = ["Hello, World!\n", "Hello, Python!"]
fp = open(r"D:\Documents\Desktop\text.txt", 'r+')
print("写入前:文件读写位置为{}".format(fp.tell()))
fp.writelines(content)
print("写入后:文件读写位置为{}".format(fp.tell()))
fp.seek(0)              # 将指针指向文件开始位置
print("移动指针:文件读写位置为{}".format(fp.tell()))
print(fp.read())
fp.close()
写入前:文件读写位置为0
写入后:文件读写位置为29
移动指针:文件读写位置为0
Hello, World!
Hello, Python!

  首先,一开始打开文件时文件指针指向0,将内容写入文件后,指向文件末尾(最后一个字节/字符的下一个位置,注意此处文件末尾最后一个字符为EOF(end of file),即文件终止标识符),通过fp.seek(0)将指针重新指向文件开始位置,之后进行读操作。

3.3 文件的异常处理

  文件的常见操作为读写操作,而在文件的操作过程中有时会发生一些异常情况导致严重后果,比如文件打开后未关闭等,通常需要利用之前介绍的try-finally结构来进行文件的异常处理和关闭:

# text.txt中有Hello, World!\nHello, Python!的内容
try:
    fp = open(r"D:\Documents\Desktop\text.txt", 'r')
    for line in fp:              # 逐行读取文件
        print(line, end = ' ')
except IOError:                  # 报告异常情况
    print("Cannot open the file!")
finally:						 # 关闭文件
    fp.close()

  在上面的程序中,无论是正常情况还是发生异常,都会执行fp.close()语句,从而避免异常情况带来的不良后果。不过在python中还提供了上下文管理器的概念,上下文管理器可以定义和控制代码块执行前的准备动作以及执行后的收尾动作,因此可以自动为代码提供收尾工作。上下文管理器的实现需要通过with语句来实现:

   with 上下文管理表达式 as 变量:
     语句序列

  with语句将上下文管理表达式的值赋给变量,并执行其语句序列,对于上面的程序可以利用with语句将其进一步简化:

# with语句与文件的读写操作
with open(r"D:\Documents\Desktop\text.txt", 'r') as fp:
    for line in fp:
        print(line, end = ' ')

  上面的程序会以只读模式打开文件text.txt,并将创建的文件对象赋值给变量fp,之后执行for循环。在这个过程中,with语句在文件结束后会自动关闭文件,因此不需要close()方法,可以看到利用with语句更加简洁和安全,因此是文件操作的推荐使用方法。

  经过上面的介绍,熟悉了对文件的操作,并掌握了异常处理方法之后,通过文件便可以处理大规模的数据,从而高效、安全地处理文件和数据了。

  至此,python基础系列的讲述就结束了,在掌握python基础语法和常用数据类型之后可以针对一些实际问题编写简单的python程序进行处理,解决一些简单的问题,不过这些还是一些入门的介绍,需要读者在平时多实践多编程来掌握。在之后的python系列中,将会涉及python的一些高级主题,比如python中面向对象程序设计的概念,还会讲述python的实践与应用,比如python科学计算、现代密码学算法实现、数据挖掘和分析等应用,这些将在之后的课程进行介绍,敬请期待!

猜你喜欢

转载自blog.csdn.net/Stu_YangPeng/article/details/118276268