什么是文件

文件就是以硬盘为载体存储信息的集合

代码操作文件的基本流程

  1. 打开文件、创建文件
  2. 编辑文件内容
  3. 保存文件内容
  4. 关闭文件

基本语法结构

语法

  1. # 完整语法格式
  2. open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

参数

  • file: 必需,文件路径(相对或者绝对路径)。
  • mode: 可选,文件打开模式
  • buffering: 设置缓冲
  • encoding: 一般使用utf8
  • errors: 报错级别
  • newline: 区分换行符
  • closefd: 传入的file参数类型
  • opener: 设置自定义开启器,开启器的返回值必须是一个打开的文件描述符

mode参数:

访问模式 描述
r (read) 只读模式,不能写(文件必须存在,不存在会报错)
w (write) 只写模式,不能读(文件存在则会被覆盖内容(要千万注意),文件不存在则创建)
a (append) 追加模式,不能读,文件不存在在则创建
r+ 读写模式
w+ 写读模式
a+ 追加读模式
rb 二进制读模式
wb 二进制写模式
ab 二进制追加模式
rb+ 二进制读写模式
wb+ 二进制写读模式
ab+ 二进制追加读模式

结构1(了解即可)

  1. f = open()
  2. f = close()

使用

  1. open(r'a.txt') # 相对路径,以后写路径为了防止特殊符号 前面直接加r
  2. open(r'/Users/kevin/Desktop/a.txt') # 绝对路径
  3. # open(文件的路径,文件的操作模式,文件的编码)
  4. res = open(r'a.txt', 'r', encoding='utf8')
  5. print (res.read()). # 读取文件内容
  6. res.close() # 关闭文件

结构2(推荐使用)

  1. # 1. 在执行完子代码块后,with 会自动执行f.close(),f为变量名
  2. with open() as f:
  3. pass # 补全语法结构 本身没有任何功能
  4. # 2、可用用with同时打开多个文件,用逗号分隔开即可
  5. with open() as f,open() as f:
  6. pass

使用

  1. with open('a.txt','r') as read_f,open('b.txt','w') as write_f:
  2. data = f.read()
  3. print(data)

文件的操作模式

r 模式

只读模式,只能读不能写

使用

  1. with open(r'a.txt', 'r', encoding='utf8') as f:
  2. print(f.read())
  3. # 今天你努力了吗?

补充:路径不存在会直接报错!

w模式

只写模式,只能写不能读

使用

  1. with open(r'a.txt', 'w', encoding='utf8') as f:
  2. f.write('今天你写代码了吗?')

文件处理 - 图1

  1. with open(r'b.txt', 'w', encoding='utf8') as f1:
  2. # 换行最早的时候:\r\n,为了节省空间支持一个字符,根据操作系统的不同可能有所区别
  3. f1.write('hhhh\n')
  4. f1.write('hhhh\n')
  5. f1.write('hhhh\n')

补充:路径不存在:自动创建文件,路径存在,先清空文件内容 之后再写入数据

a模式

只追加模式,在文件末尾添加内容

使用

  1. with open(r'a.txt', 'a', encoding='utf8') as f:
  2. f.write('hhhh')

文件处理 - 图2

补充:路径不存在,自动创建文件,路径存在,不会清空文件内容而是在文件末尾等待新内容的添加

t模式

文本模式,是默认的模式

使用

  1. with open(r'a.txt', 'rt', encoding='utf8') as f:
  2. pass
  3. with open(r'a.txt', 'rw', encoding='utf8') as f:
  4. pass
  5. with open(r'a.txt', 'ra', encoding='utf8') as f:
  6. pass

补充:

  1. 只能操作文本文件
  2. 必须要指定encoding参数
  3. 读写都是以字符串为最小单位

b模式

二进制模式 ,可以操作任意类型的文件

使用

  1. with open(r'a.txt', 'rb') as f:
  2. pass
  3. with open(r'a.txt', 'rb') as f:
  4. pass
  5. with open(r'a.txt', 'rb') as f:
  6. pass

补充:

  1. 可以操作任意类型的文件
  2. 不需要指定encoding参数
  3. 读写都是以bytes类型为最小单位

文件内置方法

  1. file.close() # 关闭文件
  2. file.write(str) # 写入文件内容(字符串或者bytes类型)
  3. file.writelines(sequence) # 可以将列表多个元素写入文件
  4. file.writable() # 判断文件是否可写
  5. file.read([size]) # 一次性读取文件内容,光标会移动到文件末尾
  6. file.readline([size]) # 一次只读一行内容,用for可以代替
  7. file.readlines([size]) # 结果是一个列表 里面的各个元素是文件的一行行内容
  8. file.readable() # 判断当前文件是否可读
  9. file.seek(offset[sizeint]) # 移动文件读取指针到指定位置
  10. file.tell() # 获取光标基于文件开头的字节数
  11. file.flush() # 相当于主动按了ctrl+s(保存)
  12. file.isatty() # 文件连接到一个终端设备返回 True or False
  13. file.next() # Python 3 不支持 next() 方法,返回文件下一行

文件光标移动

  1. with open (r'a.txt', 'r', encoding='utf8') as f:
  2. print(f.read(3)) # read在文本模式下,括号内的数字表示的是读取指定的字符个数
  3. # 今天你
  1. with open (r'a.txt', 'rb') as f:
  2. print(f.read(3)) # read在二进制模式下,括号内的数字表示的是读取指定的字节数
  3. # b'\xe4\xbb\x8a'
  4. print(f.read(3).decode('utf8'))
  5. # 天
  6. unicode所有的字符都是用2bytes来起步表示

控制光标的移动

因为文件内指针的移动都是由读/写操作而被动触发的,若想读取文件中某一个特定位置的数据,则需要用file.seek方法主动控制文件内指针的移动

语法

  1. fileObject.seek(offset, whence)
  2. # offset -- 开始的偏移量,也就是代表需要移动偏移的字节数,如果是负数表示从倒数第几位开始
  3. # whence -- 可选,默认值为 0。给 offset 定义一个参数,表示要从哪个位置开始偏移;
  4. # 0 表示从文件开头开始算起 (支持文本模式和二进制模式)
  5. #. 1 表示从当前位置开始算起 (只支持二进制模式)
  6. # 2 表示从文件末尾算起 (只支持二进制模式)
  7. # 如果操作成功,则返回新的文件位置,如果操作失败,则函数返回 -1

使用

注:这里我a文本的是“今天你写代码了吗”,一共25个字节

参数**whence**是0

  1. with open(r'a.txt', 'rb') as f:
  2. print(f.read(3).decode('utf8'))
  3. # 今
  4. print(f.seek(1)) # 从文件头开始,所以返回位置1
  5. # 1

参数**whence**是1

  1. with open(r'a.txt', 'rb') as f:
  2. print(f.read(3).decode('utf8'))
  3. # 今
  4. print(f.seek(1, 1)) # '今'字占三个字节,参数1为当前位置,所以返回位置4
  5. # 4

参数**whence**是2

  1. with open(r'a.txt', 'rb') as f:
  2. print(f.seek(1, 2)) # 从文尾开始,往前移动一个字节
  3. # 25
  4. with open(r'a.txt', 'rb') as f:
  5. print(f.seek(-1, 2)) # 从文尾开始,往前移动一个字节
  6. # 23

文件修改

了解

  1. with open(r'a.txt', 'r+t', encoding='utf8') as f:
  2. f.seek(9) # 默认是0模式,从文件开头开始
  3. f.write('去') # 因为光标读了九个字节,然后写入‘去’(3个字节),所以把‘写’覆盖掉了
  4. # 今天你去代码了吗

补充:文件数据硬盘的内容只能“覆盖”,不能“删除”

思路一

将文件内容发一次性全部读取到内存中,然后在内存中修改完毕后再覆盖写回原文件

  1. with open('a.txt', mode='r', encoding='utf-8') as f:
  2. data = f.read()
  3. with open('a.txt', mode='w', encoding='utf-8') as f:
  4. f.write(data.replace('去', '写'))
  • 优点:在文件修改过程,只有一份数据
  • 缺点:如果文件数据大,会过占用过多的内存空间

思路二

以读的方式打开原文件,以写的方式打开一个临时文件,一行行读取原文件内容,修改完后写入临时文件

  1. import os # 模块
  2. with open('a.txt', 'r', encoding='utf-8') as read_f, \
  3. open('a.txt.swap', 'w', encoding='utf-8') as wrife_f:
  4. for line in read_f:
  5. wrife_f.write(line.replace('写', '敲'))
  6. os.remove('a.txt') # 删除文件
  7. os.rename('a.txt.swap', 'a.txt') # 重命名文件
  • 优点:不会占用过多的内存
  • 缺点:在文件修改过程中同一份数据存了两份