Python笔记_第一篇_面向过程_第一部分_7.文件的操作(.txt)

  在平时,我们不光要对程序内的代码进行输入和输出的操作,还要对程序外的文件进行和语言之间的交换、操作和运算。在基础部分,先讲解对于外部的.txt文件的操作。

第一部分 基本内容讲解

1.   什么是文件操作?

  平时在进行操作的时候,都是在内存层面进行操作,但是随着程序的关闭,信息也将小时。文件操作的方式就是把操作的内容保存在硬盘上,方便随时进行增、删、改、查的操作。

 

2.   操作流程

  (1) 打开文件,得到文件句柄并赋值给一个变量(有一个函数f.fileno(),查看当前的操作句柄编码)。在这里我们要有句柄的概念,在语言中,文件从外部获取后,通过句柄取拿取文件想要的内容。

  (2) 通过句柄对文件进行操作。

  (3) 关闭文件(这个操作是必须的)。

 

3.   注意:

  (1) 比如在window系统,一个hello.txt文件是utf8保存的,打开文件是open函数是通过操作系统打开文件,而windows操作系统默认是gbk编码,所以直接打开会乱码,需要f = open('hello.txt', encoding = 'utf-8'),这样打开。

  (2) 文件的操作还要有指针的概念,通过指针读写光标的位置(内部指针的移动)。

 

第二部分 相关函数和操作演示

1.   基本函数  

  函:f.fileno

    语:f.fileno()

      用:获得当前函数句柄的编号。

 1 f = open("咏梅", "r", encoding="utf-8")
 2 fno = f.fileno()
 3 print(fno)
 4 # print(f.fileno()) # 也可以直接打印观察
 5 # 输出结果:3
 6 
 7 f1 = open("咏梅", "r", encoding="utf-8")
 8 fno1 = f1.fileno()
 9 print(fno1)
10 # print(f1.fileno()) # 也可以直接打印观察
11 # 输出结果:4

  函:f.name

    语:f.name()

      用:获得当前文件的文件名。

  举例:略

 

2.   四个基本操作:开、读、写、关

  “开”:

  函:open

    语:open("file", "mode", buffering =None , encoding = None, errors = None, newline = None, closefd = True)

      用:

  (1) "file"----文件名/路径+文件名 (如果是相对路径直接填写文件名即可),需要加引号

  (2) "mode"----读取模式:

      "r"---- 只读模式

      "w"---- 写模式

      "a"---- 追加内容模式(光标位置在最后)

      "x" ---- 打开一个单独创作的文件,如果失败将会返回。

      "t" ---- 以文本模式打开(缺省模式)

      "b" ---- 二进制模式

      "U" ---- 通用换行符

      "rb" ---- 读取二进制文件

      "wb" --- 写二进制文件

      "ab" ---- 追加二进制文件

      "+" ---- 加模式用于下面的几种组合:

      "r+"---- 读写/写读模式(光标位置不同), 属于加模式下

      "w+"---- 写读/读写模式(光标位置不同), 属于加模式下

      "a+"---- 追读/读追模式(光标位置不同), 属于加模式下

  (3) buffering = ---- 可取的值有0、1、>1 三种,0表示buffer关闭(只适用于二进制模式),1代表line buffer(只适用于文本模式),>1表示初始化的buffer大小。

  (4) encoding = ---- 编码模式

  (5) errors = ---- 错误忽略模式(取值一般有strict、ignore,replace,当取strict的时候,字符编码出现问题的时候会报错,当取ignore的时候,编码出现问题,程序会忽略而过,绩效执行下面的程序。选择replace的时候,使用某字符进行替代模式,比如使用?来替代出错。)

  (6) newline = ---- 可取的值有None,\n、\r、"、'\r\n',用于区分换行符,但是这个参数只对文本有效。

  (7) closefd = ---- 默认情况下是True。是与传入的文件参数有关,传入file参数为文件的文件名,取值为false的时候,file只能是文件描述符,什么是文件描述?就是一个非负的整数,在Unix内核的系统中,打开一个文件,变回返回一个文件描述。

  

  “读”:

  函:f.read、f.readline、f.readlines、f.readable

    语:f.read(n)、f.readline(n)、f.readlines(n)、f.readable

      用:f.read(n):默认为读取文本中所有的内容,n为从开始读几个字符。输出为字符串格式。

        f.readline(n):默认为读取文本的第一行内容,n为某一行开始读几个字符。输出为字符串格式。

        f.readlines(n):默认按照行的排列,读取所有的行,n为对应所有字符的位置,如果当前字符位在某一行内,直接返回读取到当前的行。输出为列表类型。

        f.readable():判断句柄文字是否可读,返回真True或者False。

  

  “写”:

  函:f.write、f.writelines、f.writeable

    语:f.write("str")、f.writelines(list)、f.writeable()

      用:f.write("str"):写入括号字符串中的内容。

        f.writelines(list):根据一个列表内容添加到文本中。跟上面的f.realines一样,f.realines是把内容读出到列表中;f.writelines是把列表添加到文本中。

        f.writeable:返回值为False或者True,表示当前句柄内容是否可写。

 

  “关”:

  函:f.close

    语:f.close()

      用:关闭一个文档。

 

3.   根据上面的四类函数进行详细的讲解

3.1   一个最简单的操作并读取文件的过程。

  代码如下:

 1 # 一个简单的打开和操作 #
 2 # 第一种打开方式:"r":只读模式
 3 data = open("咏梅", "r", encoding="utf-8").read()
 4 print(data)
 5 print(type(data), "\n")
 6 # 输出结果:
 7 # 风雨送春归,
 8 # 飞雪迎春到。
 9 # 已是悬崖百丈冰,
10 # 犹有花枝俏。
11 #
12 # 俏也不争春,
13 # 只把春来报。
14 # 待到山花烂漫时,
15 # 她在丛中笑。
16 # <class 'str'>
17 
18 # 第二种打开方式:采用函数句柄的方式打开文件。"r":只读模式
19 f = open("咏梅", "r", encoding="utf-8")
20 data = f.read()
21 print(data)
22 print(type(data), "\n")
23 # 输出结果:
24 # 风雨送春归,
25 # 飞雪迎春到。
26 # 已是悬崖百丈冰,
27 # 犹有花枝俏。
28 #
29 # 俏也不争春,
30 # 只把春来报。
31 # 待到山花烂漫时,
32 # 她在丛中笑。
33 # <class 'str'>

  分析知识点:

  (1) 第一种方式为用只读方式简单的打开了一个文件,采用面向对象类的访问方式.read()的方式打开文件。

  (2) 第二种方式,用open函数打开文件后,赋值到一个句柄f当中,后面的所有操作都是根据句柄f展开的。我们看到这两种方式效果一样,但是建议采用后者,逻辑更清晰。

  (3) open函数一种最常用的格式为open("文件名", "读取模式", “编码格式”),这个必须记住。

  (4) 在这里我们用到了f.read的函数,根据另外两个read函数进行演示,以第二种方式为例。

 

  代码如下:

 1 # 例子1:只读取前三个字符(英文1个单词一个字符,中文1个字两个字符)
 2 # 方法一:
 3 f = open("咏梅", "r", encoding="utf-8")
 4 data = f.read(3)
 5 print(data)
 6 print(type(data))
 7 # 输出结果:
 8 # 风雨送
 9 # <class 'str'>
10 
11 # 方法二:
12 f = open("咏梅", "r", encoding="utf-8")
13 data = f.readline(3)
14 print(data)
15 print(type(data))
16 # 输出结果:
17 # 风雨送
18 # <class 'str'>
19 
20 # 例子2:用列表形式读取所有的内容
21 f = open("咏梅", "r", encoding="utf-8")
22 data = f.readlines()
23 print(data)
24 print(type(data))
25 # 输出结果:
26 # ['风雨送春归,\n', '飞雪迎春到。\n', '已是悬崖百丈冰,\n', '犹有花枝俏。\n', '\n', '俏也不争春,\n', '只把春来报。\n', '待到山花烂漫时,\n', '她在丛中笑。']
27 # <class 'list'>
28 
29 # 例子3:用列表的形式只读取前两行内容
30 f = open("咏梅", "r", encoding="utf-8")
31 data = f.readlines()
32 print(data[0:2])
33 print(type(data))
34 # 输出结果:
35 # ['风雨送春归,\n', '飞雪迎春到。\n']
36 # <class 'list'>
37 
38 # 例子4:用列表的形式只读取前两行内容,并把内容转换成字符串形式。
39 f = open("咏梅", "r", encoding="utf-8")
40 data = f.readlines()
41 data1 = data[0]
42 data2 = data[1]
43 data3 = data1 + data2
44 print(str(data3))
45 print(type(data3))
46 # 输出结果:
47 # 风雨送春归,
48 # 飞雪迎春到。
49 # 
50 # <class 'str'>

  分析知识点

  (1) 从f.readlines和f.readline函数中我们可以看到f.readlines这个函数返回的结果是list(列表)类型,然后再通过查找列表的第几个元素,就是对应的第几行。

  (2) python对于选取行数的方式用转移成list的方式进行实习,通过list的下标再找到第几行

 

3.2    借用上面的例子,把读取的文件在最后光标位添加内容

  代码如下:

 1 # 例子1:在咏梅这首诗光标最后位置添加一段内容。
 2 f = open("咏梅", "a+", encoding="utf-8")
 3 data = f.write("大将生来胆气寒")
 4 f.seek(0)        # 这个函数下面会讲
 5 data1 = f.read()  # 这个时候文件指针放到最后一个字符,要用seek恢复指针。
 6 print(data1)
 7 f.close()
 8 # 输出结果:
 9 # 风雨送春归,
10 # 飞雪迎春到。
11 # 已是悬崖百丈冰,
12 # 犹有花枝俏。
13 #
14 # 俏也不争春,
15 # 只把春来报。
16 # 待到山花烂漫时,
17 # 她在丛中笑。大将生来胆气寒 # 在结尾出添加了一句话。
18 
19 # 例子2:在结尾处的下一行添加一段内容。
20 f = open("咏梅", "a+", encoding="utf-8")
21 data = f.write("\n大将生来胆气寒")   # 在开始添加一个换行符
22 f.seek(0)        # 这个函数下面会讲
23 data1 = f.read()  # 这个时候文件指针放到最后一个字符,要用seek恢复指针。
24 print(data1)
25 f.close()
26 # 输出结果:
27 # 风雨送春归,
28 # 飞雪迎春到。
29 # 已是悬崖百丈冰,
30 # 犹有花枝俏。
31 #
32 # 俏也不争春,
33 # 只把春来报。
34 # 待到山花烂漫时,
35 # 她在丛中笑。
36 # 大将生来胆气寒  # 添加在这里
37 
38 # 例子3:观察打开的文件是否可写,如果可写用f.writelines的方式添加另外一首诗进去。
39 # 然后判断句柄是否可读,如果可读把文章读出来。
40 f = open("咏梅", "a+", encoding="utf-8")
41 if f.writable() == True:   # 判断文章是否可写
42     list = ["\n锄禾日当午,", "\n汗滴禾下土。", "\n谁知盘中餐,", "\n粒粒皆辛苦。"]
43     f.writelines(list)
44 f.seek(0)
45 if f.readable() == True:  # 判断文章是否可读
46     data = f.read()
47     print(data)
48 f.close()
49 # 输出结果:
50 # 风雨送春归,
51 # 飞雪迎春到。
52 # 已是悬崖百丈冰,
53 # 犹有花枝俏。
54 #
55 # 俏也不争春,
56 # 只把春来报。
57 # 待到山花烂漫时,
58 # 她在丛中笑。
59 #
60 # 锄禾日当午,
61 # 汗滴禾下土。
62 # 谁知盘中餐,
63 # 粒粒皆辛苦。

  分析知识点:

  (1) f.writelines对应上面的f.readlines返回的值都是list列表类型,通过写一个list列表可以多行来进行添加。

  (2) f.seek移动光标位置,如果不移动的话,将读取不了文件。

  (3) f.close()这个千万不要忘记。

 

3.3   回过头来我们在把open的其他几个填充参数讲解一下

  buffering:

  buffering选项是一个可选参数,平时很少用到。但是这里进行讲解一下。

  buffering用来表示缓冲区的策略选择。设置为0时,表示不使用缓冲区,直接读写,尽在二进制模式下有效。设置为1时,表示在文本模式下使用行缓冲区方式。设置为大于1时,表示缓冲区的设置大小,如果参数buffering没有给出,会使用默认策略进行选择,方式如下:

  (1) 对于二进制模式时,采用固定块内缓冲区方式,内存块的大小根据系统设置的分配磁盘块来决定,如果获取系统磁盘块的大小失败,就是用内部常量io.DEFAULT_BUFFER_SIZE定义大小。一般的操作系统上,快的大小是4096或者8192自己大小。

  (2) 对于交互式的文本采用isatty()(检测当期设备函数)来判断为True时,采用一行缓冲区的方式。其他文本文件使用跟二进制一样的方式。

  总结:换句话说基本没用。

 

  errors:

   errors选项是用来知名编码和解码错误时怎么处理。不能再二进制的模式下使用。

  (1) 当指明为  strict  时,编码出错则跑出异常ValueError

  (2) 当指明为  ignore 时,忽略错误。

  (3) 当指明为  replace 时,使用某字符进行替代模式,比如使用?来替换出错。

  我们还是用咏梅那首诗,我们开始采用的编码是utf-8编码,如果我们替换成ASCII码的解码方式,肯定是个错误,如果错误的话,分别对应这三种结果会产生什么效果。

  代码如下:

 1 # errors
 2 # 使用strict 严格方式。
 3 f = open("咏梅", "r", errors="strict", encoding="ASCII")
 4 data = f.read()
 5 print(data)
 6 # 输出结果:
 7 # 产生一个报错,不应是用ASCII码来进行解码
 8 # Traceback (most recent call last):
 9 #   File "C:/Users/Administrator/Desktop/Python-1704/day5/文件操作.py", line 221, in <module>
10 #     data = f.read()
11 #   File "F:\Users\Administrator\PycharmProjects\untitled\venv\lib\encodings\ascii.py", line 26, in decode
12 #     return codecs.ascii_decode(input, self.errors)[0]
13 # UnicodeDecodeError: 'ascii' codec can't decode byte 0xe9 in position 0: ordinal not in range(128)
14 
15 # 使用 ignore 忽略方式。
16 f = open("咏梅", "r", errors="ignore", encoding="ASCII")
17 data = f.read()
18 print(data)
19 # 输出结果:
20 # 啥都没有显示,这个解码错误被忽略了。
21 
22 # 使用 replace 替换方式。
23 f = open("咏梅", "r", errors="replace", encoding="ASCII")
24 data = f.read()
25 print(data)
26 # 输出结果:
27 # 一堆问号,错误解码用?来替代
28 # ������������������
29 # ������������������
30 # ������������������������
31 # ������������������
32 # 
33 # ������������������
34 # ������������������
35 # ������������������������
36 # ������������������

 

  newline:

  newline是用来控制文本模式之下一行的结束字符。可以是None,'  ',\n,\r,\r\n等。在当读取模式下,如果新行符为None,那么就作为通用换行符模式工作,一是是说当遇到\n,\r  或者\r\n都可以作为换行标识,并统一转换为\n作为文本输入换行符。当设置为空'  ' 时,也就是通用换行符模式工作,但不作转换为\n,输入什么样,就保持原样全输入。当设置为其他相应字符时,就会判断到相应的字符作为换行符,并保持原样输入到文本。

  当输出模式时,如果新行符为None,那么所有输出文本都是采用\n作为换行符。如果设置为'  '空或者\n时,不做任何替换动作。如果是其他字符,会出现在字符后面添加\n作为换行符。

  这个功能也是不太常用的,而且python3中,只能用f.readlines进行演示演示代码如下:

 1 # 如果默认None状态
 2 f = open("咏梅", "r+", encoding="utf-8", newline=None)
 3 data = f.readlines()
 4 print(data)
 5 # 输出结果:正常显示
 6 # ['风雨送春归,\n', '飞雪迎春到。\n', '已是悬崖百丈冰,\n', '犹有花枝俏。\n', '\n', '俏也不争春,\n', '只把春来报。\n', '待到山花烂漫时,\n', '她在丛中笑。\n']
 7 
 8 # 如果"\r"的状态
 9 f = open("咏梅", "r+", encoding="utf-8", newline="\r")
10 data = f.readlines()
11 print(data)
12 # 输出结果:用\r替代换行符\n,而\n提到前面去了。
13 # ['风雨送春归,\r', '\n飞雪迎春到。\r', '\n已是悬崖百丈冰,\r', '\n犹有花枝俏。\r', '\n\r', '\n俏也不争春,\r', '\n只把春来报。\r', '\n待到山花烂漫时,\r', '\n她在丛中笑。\r', '\n']
14 
15 # 如果"\n"的状态
16 f = open("咏梅", "r+", encoding="utf-8", newline="\n")
17 data = f.readlines()
18 print(data)
19 # 输出结果:\r\n都表示换行
20 # ['风雨送春归,\r\n', '飞雪迎春到。\r\n', '已是悬崖百丈冰,\r\n', '犹有花枝俏。\r\n', '\r\n', '俏也不争春,\r\n', '只把春来报。\r\n', '待到山花烂漫时,\r\n', '她在丛中笑。\r\n']
21 
22 # 如果"\r\n"的状态
23 f = open("咏梅", "r+", encoding="utf-8", newline="\r\n")
24 data = f.readlines()
25 print(data)
26 # 输出结果:\r\n都表示换行跟上面一样
27 # ['风雨送春归,\r\n', '飞雪迎春到。\r\n', '已是悬崖百丈冰,\r\n', '犹有花枝俏。\r\n', '\r\n', '俏也不争春,\r\n', '只把春来报。\r\n', '待到山花烂漫时,\r\n', '她在丛中笑。\r\n']
28 
29 # 如果""的状态
30 f = open("咏梅", "r+", encoding="utf-8", newline="")
31 data = f.readlines()
32 print(data)
33 # 输出结果:与上面一个一样。
34 # ['风雨送春归,\r\n', '飞雪迎春到。\r\n', '已是悬崖百丈冰,\r\n', '犹有花枝俏。\r\n', '\r\n', '俏也不争春,\r\n', '只把春来报。\r\n', '待到山花烂漫时,\r\n', '她在丛中笑。\r\n']

  

  closefd:

  是否关闭,用来给当一个文件句柄传进来时,而当退出文件使用时,而不对文件句柄进行关闭。如果传递一个文件名进来,这个参数无效,必定为True方式。

  如果为True时:传入的file参数为文件的文件名

  如果为False时:传入的file参数只能是文件描述符。

  如果Ps:文件描述,就是一个非负整数,在Unix内核的系统中,打开一个文件,变回返回一个文件描述。

 

4.    剩下一点儿就是对于mode的模式几种进行一下说明

4.1   基本模式:

  "r"----只读模式,代码如下:

 1 # 只读模式
 2 f = open("咏梅", "r", encoding="utf-8")
 3 data = f.read()
 4 print(data)
 5 f.close()
 6 # 输出结果:
 7 # 风雨送春归,
 8 # 飞雪迎春到。
 9 # 已是悬崖百丈冰,
10 # 犹有花枝俏。
11 #
12 # 俏也不争春,
13 # 只把春来报。
14 # 待到山花烂漫时,
15 # 她在丛中笑。

  分析知识点:没啥可说的,也就是打开文件只能读

 

  "w"----只写模式

 1 # 只写模式
 2 f = open("二进制文件.txt", "w", encoding="utf-8")
 3 data = f.read()
 4 print(data)
 5 f.close()
 6 # 输出结果:
 7 # Traceback (most recent call last):
 8 #   File "C:/Users/Administrator/Desktop/Python-1704/day5/文件操作.py", line 308, in <module>
 9 #     data = f.read()
10 # io.UnsupportedOperation: not readable

  分析知识点

  (1) 如果原文件不存在,文件名作为新建文件名且创建一个新的文件。

  (2) 如果源文件存在,会把原文件的内容全部覆盖掉,作为一个空文件以供添加内容。

  (3) 由于是只写模式,所以下面输出结果会报错。

 

  "a"----追加模式

 1 # 追加模式
 2 f = open("咏梅", "a", encoding="utf-8")
 3 data = f.write("作者:毛主席")
 4 print(data)
 5 f.close()
 6 # 输出模式:
 7 # 6
 8 # 文件中显示:
 9 # 风雨送春归,
10 # 飞雪迎春到。
11 # 已是悬崖百丈冰,
12 # 犹有花枝俏。
13 # 
14 # 俏也不争春,
15 # 只把春来报。
16 # 待到山花烂漫时,
17 # 她在丛中笑。("a"模式打开后,指针位与这个位置)作者:毛主席   

  分析知识点:注意一点"a"模式,指针开始会停留在最后一个字符的后面,也就是说,不添加换行等命令。是在最后一个位置进行添加。

 

  "U" ---- 通用换行符模式打开,---也就是rU简写是r等。

  "t" ---- 以文本模式打开(缺省模式)----也就是rt简写是r, wt简写是w,这个字符可以省略

 

  "b" ---- 二进制模式如下:

  "rb" ---- 读取二进制文件:

  "wb" --- 写二进制文件:

  "ab" ---- 追加二进制文件:

 1 # rb模式
 2 f = open("咏梅", "rb")
 3 # f.read()
 4 data = f.read()
 5 print(data)
 6 #print(f)    # 直接打印句柄,会显示描述文件<_io.BufferedReader name='咏梅'>
 7 # print(f.read())  # 这样还直接打印不了,显示为:b''
 8 f.close()
 9 # 输出结果:
10 # b'\xe9\xa3\x8e\xe9\x9b\xa8\xe9\x80\x81\xe6\x98\xa5\xe5\xbd\x92\xef\xbc\x8c\r\n\xe9\xa3\x9e\xe9\x9b\xaa\xe8\xbf\x8e\xe6\x98\xa5\xe5\x88\xb0\xe3\x80\x82\r\n\xe5\xb7\xb2\xe6\x98\xaf\xe6\x82\xac\xe5\xb4\x96\xe7\x99\xbe\xe4\xb8\x88\xe5\x86\xb0\xef\xbc\x8c\r\n\xe7\x8a\xb9\xe6\x9c\x89\xe8\x8a\xb1\xe6\x9e\x9d\xe4\xbf\x8f\xe3\x80\x82\r\n\r\n\xe4\xbf\x8f\xe4\xb9\x9f\xe4\xb8\x8d\xe4\xba\x89\xe6\x98\xa5\xef\xbc\x8c\r\n\xe5\x8f\xaa\xe6\x8a\x8a\xe6\x98\xa5\xe6\x9d\xa5\xe6\x8a\xa5\xe3\x80\x82\r\n\xe5\xbe\x85\xe5\x88\xb0\xe5\xb1\xb1\xe8\x8a\xb1\xe7\x83\x82\xe6\xbc\xab\xe6\x97\xb6\xef\xbc\x8c\r\n\xe5\xa5\xb9\xe5\x9c\xa8\xe4\xb8\x9b\xe4\xb8\xad\xe7\xac\x91\xe3\x80\x82'
11 # 一连串的二进制地址位。
12 
13 # wb模式
14 f = open("二进制文件", "wb")
15 f.write(b'\xe9\xa3\x8e\xe9\x9b\xa8')
16 f.close()
17 # 文本中的输出结果:
18 # 风雨         这两个汉字
19 
20 # ab模板
21 f = open("二进制文件", "ab")
22 f.write(b"\xe9\x80\x81\xe6\x98\xa5")
23 f.close()
24 # 文本中的输出结果:
25 # 风雨送春      在风雨的后面又追加两个汉字

  分析知识点

  (1) 从这三个例子可以看出,二进制的输入要用二进制地址格式进行输入,像b"地址"  或者 b'地址' 这样才能去写,写到文本中后,会自动变为字符。

  (2) 二进制读取读取出来的也是像b"地址"  或者 b'地址'这样的二进制地址位。

  (3) 如果在某一个模式下,直接print(f)句柄,会得到os.BufferedReader缓冲区对于文件的简要描述

  (4) 如果直接打印print(f.write())这样的句柄模式,会得到输入了多少个字符。如果打印print(f.read())会全部内容。

 

  "+" ---- 加模式如下

  "r+"---- 读写/写读模式,先读后写

 1 # r+模式 两种变化
 2 # 第一种:先写后读,指针从0行0位开始进行写,之前写的不动,会根据添加的字符进行不断的覆盖。
 3 f = open("二进制文件", "r+", encoding="utf-8")
 4 f.write("作者:毛主席\n作者:毛主席\n")
 5 print(f.read())
 6 f.close()
 7 # 文本显示结果:
 8 # 作者:毛主席   # 把前两行覆盖了
 9 # 作者:毛主席
10 # 已是悬崖百丈冰,
11 # 犹有花枝俏。
12 #
13 # 俏也不争春,
14 # 只把春来报。
15 # 待到山花烂漫时,
16 # 她在丛中笑。
17 
18 # 第二种:先读后写,指针从0行0位读到最后一个字符的后, 这个时候写的话,变成追加模式了。
19 f = open("二进制文件", "r+", encoding="utf-8")
20 print(f.read())
21 f.write("作者:毛主席")
22 f.close()
23 # 文本显示结果:
24 # 风雨送春归,
25 # 飞雪迎春到。
26 # 已是悬崖百丈冰,
27 # 犹有花枝俏。
28 # 
29 # 俏也不争春,
30 # 只把春来报。
31 # 待到山花烂漫时,
32 # 她在丛中笑。作者:毛主席   # 此时指针读完,放到最后,进行追加了。

  分析知识点

  (1) r+模式是r + w 模式的组合。

  (2) r+模式注意指针的变化

 

  "w+"---- 写读/读写模式

1 # w+ 模式
2 f = open("二进制文件", "w+", encoding="utf-8")
3 f.write("作者:毛主席")
4 f.close()
5 # 文本中显示结果:
6 # 作者:毛主席

  分析知识点

  (1) w+模式是w + r 模式的组合。

  (2) w+模式注意指针的变化

 

  "a+"---- 追读/读追模式

1 # a+ 模式
2 f = open("二进制文件", "a+", encoding="utf-8")
3 str = ["\n风雨送春归,", "\n飞雪迎春到"]
4 f.writelines(str)
5 f.close()
6 # 文本中显示结果:
7 # 作者:主席
8 # 风雨送春归,
9 # 飞雪迎春到

  分析知识点

  (1) a+模式是a + r 模式的组合。

  (2) a+模式注意指针的变化

 

第三部分 其他文件的操作方法

 1.   遍历打印方式

  之前我们知道用f.readlines()是输出了一个列表的形式,我们前面的代码访问具体的内容是用下标的方式,其实我们也可以用for遍历的方式也是一样的。

  用简单for循环的方式进行遍历,代码如下:

 1 # 遍历的方式打印所有的行
 2 f = open("咏梅", "rt", encoding="utf-8")
 3 for i in f.readlines():
 4    print(i.strip())   # 如果不加strip,会多换一行,一般要加上一个strip()保持和原先文章一致
 5 # 输出结果:
 6 # 风雨送春归,
 7 # 飞雪迎春到。
 8 # 已是悬崖百丈冰,
 9 # 犹有花枝俏。
10 # 
11 # 俏也不争春,
12 # 只把春来报。
13 # 待到山花烂漫时,
14 # 她在丛中笑。

  用列表的方式进行遍历,代码如下:

1 # 用列表的方式 进行遍历
2 f = open("咏梅", "rt", encoding="utf-8")
3 f = f.readlines()
4 num = 0
5 while num < len(f):
6     print(f[num].strip())
7     num += 1

  用枚举的方式进行遍历,代码如下

 1 # 用枚举的方式进行遍历
 2 f = open("咏梅", "rt", encoding="utf-8")
 3 for i, v in enumerate(f.readlines(), 1): # 这是for 内部将f对象做成一个迭代器,用一行取一行
 4     print(i, v.strip())
 5 print(type(i))
 6 print(i)  # 迭代到最后一行
 7 # 显示结果:
 8 # 1 风雨送春归,
 9 # 2 作者:毛主席
10 # 3 飞雪迎春到。
11 # 4 已是悬崖百丈冰,
12 # 5 犹有花枝俏。
13 # 6
14 # 7 俏也不争春,
15 # 8 只把春来报。
16 # 9 待到山花烂漫时,
17 # 10 她在丛中笑。
18 # <class 'int'>
19 # 10

  分析知识点:在这里遍历打印的时候i.strip()是常用的一种技巧,目的是为了在strip前后无效的\n\t这些位置去除掉。

 

2.   我们把咏梅的诗歌,第二行显示“作者:毛主席”,然后把第二行的毛主席显示一个字符串,用两种方式:

  代码如下:

 1 # 方法一:传统方法
 2 f = open("咏梅", "rt", encoding="utf-8")
 3 num = 0
 4 for i in f.readlines():
 5     num += 1
 6     if num == 2:   # 如果读到第二行
 7         print(i.strip(), end="  你回答的很正确")
 8     else:
 9         print(i.strip())
10 f.close()
11 # 显示结果:
12 # 风雨送春归,
13 # 作者:毛主席  你回答的很正确飞雪迎春到。
14 # 已是悬崖百丈冰,
15 # 犹有花枝俏。
16 #
17 # 俏也不争春,
18 # 只把春来报。
19 # 待到山花烂漫时,
20 # 她在丛中笑。
21 
22 # 方法2:用join链接字符串的方式
23 f = open("咏梅", "rt", encoding="utf-8")
24 number = 0
25 for i in f.readlines():
26     number += 1
27     if number == 2:
28         i = "".join([i.strip(), "  你回答的很正确"])  # 取代万恶的加号,字符串拼接
29     print(i.strip())
30 # 显示结果:
31 # 风雨送春归,
32 # 作者:毛主席  你回答的很正确
33 # 飞雪迎春到。
34 # 已是悬崖百丈冰,
35 # 犹有花枝俏。
36 #
37 # 俏也不争春,
38 # 只把春来报。
39 # 待到山花烂漫时,
40 # 她在丛中笑。

 

3.   文件操作的其他几个内建函数

  函:f.tell

    语:f.tell(n)

      用:检测光标(指针)当前的位置。注意:tell中文对应的光标和英文对应的光标占用位不一样(中文一般2个字符,英文一般一个字符)

 

  函:f.seek

    语:f.seek(n)

      用:调整或移动光标(指针)当前的位置。注意seek和tell是意义对应的关系。通过seek调整光标的位置。起始位为:0

   举例如下:

 1 # tell(n)
 2 # 作用:检测光标(指针)当前的位置
 3 # 注意:tell中文对应的光标和英文对应的光标显示位置不一样
 4 f = open("咏梅", "rt", encoding="utf-8")
 5 print(f.tell())  # 刚开始光标在0的位置
 6 print(f.read(4))
 7 print(f.tell())  # read了5个位置光标移动到12,中文占三个字符,英文是1个字符
 8 # 显示结果:
 9 # 0
10 # 风雨送春   中文字符占2个位。
11 # 12        现在光标到12的位置。
12 
13 # seek(n)
14 # 作用:调整光标(指针)当前的位置
15 # 注意 seek和tell是一一对应的关系。通过seek调整光标的位置。
16 f = open("咏梅", "rt", encoding="utf-8")
17 print(f.read(1))
18 print(f.read(2))
19 print(f.read(3))
20 f.seek(0) # 重新调整光标位置到第一个,重新读
21 print(f.read(1))
22 # 显示结果:
23 # 风  开始读取一个中文字
24 # 雨送  然后再继续读两个中文字
25 # 春归,然后再继续读3个中文字(含1个字符)
26 # 风   # 回复到第一的位置

 

  函:flush

    语:f.flush()

      用:这个函数的作用是把缓存里面的数据转存到硬盘里面(一般用于进度条制作)。方法是用来刷新缓冲区的,即将缓冲区中的数据立刻写入文件,同时清空缓冲区,不需要被动的等待输出缓冲区写入。一般情况下,文件关闭后会自动刷新缓冲区,但是有时候你需要在关闭前刷新他,这时就可以用f.flush的方法。注意:可以理解为:平时都是执行完一段代码滞后才能看见。用这个方法,可以边看边执行。

  举例代码如下:

 1 f = open("helloworld", "w")
 2 f.write("Thomas is 35")
 3 print(f.name)
 4 f.write('hello \n')  # 执行一条
 5 f.flush() # 刷新到文件中一条
 6 f.write('world\n') # 执行一条
 7 f.close() # 刷新到文件中一条
 8 # 文件中显示的结果:
 9 # Thomas is 35hello
10 # world
11 
12 import sys,time
13 f = open("hello001", "w", encoding="utf-8")
14 f.write("hello")
15 for i in range(10):
16     sys.stdout.write("*")
17     sys.stdout.flush()
18     time.sleep(0.5) # 按照0.5秒的速度刷新
19 # 显示内容:
20 # **********
21 # Process finished with exit code 0

  分析知识点:这里运用了库文件sys和time,这个后面会讲到。

 

  函:truncate

    语:truncate(n)

      用:截断功能、默认是光标从第一个位置开始全部删除。如果设定参数设定,可以从设定的位置后面的所有内容都给截断。注意:这里打开文件的内容不能用w模式,因为w模式本身先进行一遍truncate过程。所以再用truncate会出错的。括号当中的n为从第几个字符进行截断,这里的中文字符再truncate函数中为3个字符为一个汉字。默认是从0开始,等同于w模式。

  举例如下:

 1 # truncate() 函数
 2 # 作用:截断功能、默认是光标是从第一个位置开始全部删除。如果设定参数设定,可以从设定的位置
 3 #      后面的所有内容都给接触
 4 # 注意:这里打开文件模式不能用w模式。w本身要先进行一遍truncate过程。所以再用truncate会出错。
 5 # 原文章:
 6 # 风雨送春归,
 7 # 飞雪迎春到。
 8 # 已是悬崖百丈冰,
 9 # 犹有花枝俏。
10 #
11 # 俏也不争春,
12 # 只把春来报。
13 # 待到山花烂漫时,
14 # 她在丛中笑。
15 f = open("咏梅", "a", encoding="utf-8")
16 f.truncate(3)
17 f.close()
18 # 显示结果:
19 #

 

4.   文件的修改问题

  针对上面的内容,如果对一个文件进行修改是比较麻烦的,其实可以通过重写一份的方式进行文件的修改,类似于深拷贝的形式。很像一遍拿着课本,抄一遍,然后把要修改的地方记录下来。

  举例代码:

 1 # 文件的修改问题 #
 2 # 把一整行进行替换
 3 f_read = open("咏梅", "r", encoding="utf-8")
 4 f_write = open("咏梅2", "w", encoding="utf-8")
 5 
 6 number = 0
 7 for line in f_read:
 8     number += 1
 9     if number == 5:
10         line = "hello 毛主席\n"   # 这样把第五行进行替换了
11     f_write.write(line)
12 f_write.close()
13 f_read.close()
14 # 显示结果:
15 # 风雨送春归,
16 # 飞雪迎春到。
17 # 已是悬崖百丈冰,
18 # 犹有花枝俏。
19 # hello 毛主席
20 # 俏也不争春,
21 # 只把春来报。
22 # 待到山花烂漫时,
23 # 她在丛中笑。
24 
25 # 在一段后面添加字符串
26 f_read = open("咏梅", "r", encoding="utf-8")
27 f_write = open("咏梅2", "w", encoding="utf-8")
28 
29 number = 0
30 for line in f_read:
31     number += 1
32     if number == 5:
33         line = "".join([line.strip(), "hello 毛主席\n"])
34         # line = "hello 毛主席\n"   # 这样把第五行进行替换了
35     f_write.write(line)
36 f_write.close()
37 f_read.close()
38 # 显示结果:
39 # 风雨送春归,
40 # 飞雪迎春到。
41 # 已是悬崖百丈冰,
42 # 犹有花枝俏。
43 # hello 毛主席
44 # 俏也不争春,
45 # 只把春来报。
46 # 待到山花烂漫时,
47 # 她在丛中笑。

 

5.   一个重要的知识点 with... as ...在文件操作中的应用

   为了避免打开文件后忘记关闭,可以通过with语句管理上下文。with语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源。比如文件使用后自动关闭、线程中的会自动获取和释放等。而且用with... as...的方式还可以同时打开多个文件

  语法:with  context_expression  [as target(s)]:

        with_body

 1 # with
 2 # 作用:为了避免打开文件后忘记关闭,可以通过with语句管理上下文。
 3 # with 语句适用于对资源进行访问的场合,确保不管使用过程中是否
 4 # 发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、
 5 # 线程中锁的自动获取和释放等。
 6 # 语法:
 7 # with context_expression [as target(s)]:
 8 #     with-body
 9 with open("咏梅", "r", encoding="utf-8") as f:
10      f.readline()
11      f.read()
12 print("成功打开")
13 # 显示结果:成功打开
14 
15 
16 # 同样with语句在python3当中可以打开多个文件
17 with open("咏梅", "r", encoding="utf-8") as f, open("咏梅2", "w", encoding=\
18      "utf-8") as f_write:
19     for i in f.readlines():
20         print(i.strip())
21 # 显示结果:
22 # 风雨送春归,
23 # 飞雪迎春到。
24 # 已是悬崖百丈冰,
25 # 犹有花枝俏。
26 # 
27 # 俏也不争春,
28 # 只把春来报。
29 # 待到山花烂漫时,
30 # 她在丛中笑。

 

6.   其他补充

  记得在标准化输入输出当中,print函数中有个参数为file = file.name。其实我们也可以通过print的函数来替代f.write函数把想要写的内容,打印到文件中。但是要注意的是,必须先要建立文件。

  举例如下:

1 with open("李白", "w", encoding="utf-8") as f:
2     print("长风破浪会有时,直挂云帆济沧海", file=f)
3 # 文件中的显示结果:
4 # 长风破浪会有时,直挂云帆济沧海  # 是不是也是一样呢?

 

总结

  关于文件的操作,这里是基本操作,还有一些csv,png(图片),mp4(图像),wmv(声音)等高级文件操作方式,后面会有相关专题来进行讲解。

 

posted @ 2018-02-10 05:50  时海涛|Thomas  阅读(338)  评论(0编辑  收藏  举报