1 # 应用程序运行过程中产生的数据都是存放在内存中的,若想永久保存下来,必须存放在硬盘中
  2 # 应用程序操作硬件必须通过操作系统,而文件就是操作系统提供给应用程序来操作硬盘的虚拟概念
  3 # 用户或者应用程序对文件的操作,就是向操作系统发起调用,然后由操作系统完成对硬盘的具体操作
  4 # 有了文件的概念,我们无需考虑操作硬盘的细节,只需要关注文件操作即可
  5 
  6 # 打开文件,由应用程序向操作系统发起系统调用open(),操作系统打开该文件,对应一块硬盘空间,并返回一个文件对象赋值给一个变量f
  7 f = open('a.txt', 'r', encoding='utf-8')
  8 # 调用文件下的读/写方法,会自动转成硬盘的读/写操作
  9 data = f.read()
 10 # 打印读出来的数据
 11 print(data)
 12 
 13 # 向操作系统发起关闭文件的请求,回收系统资源
 14 f.close()  # 回收变量操作系统打开的文件资源
 15 del f  # 回收应用程序级
 16 print(f)
 17 
 18 # 资源回收和with上下文管理
 19 # 打开一个文件包含两部分资源:应用程序的变量f和操作系统打开的文件。
 20 # 在操作完毕一个文件时,必须把这两部分资源全部回收
 21 # del f 一定要发生在f.close()之后,否则就会导致操作系统打开的文件无法关闭,白白
 22 # 占用资源
 23 
 24 # python自动垃圾回收机制决定了我们无需考虑del f,这就要求我们在操作文笔文件后
 25 # 一定要f.close(),虽然我们如此强调,但是大多数的人还是会忘记f.close()
 26 # 考虑到这一点,python提供了with关键字来帮我们管理上下文
 27 # 可用with打开多个文件,中间用,分隔就行
 28 with open('a.txt', 'r', encoding='utf-8') as read_f, open('b.txt', 'w', encoding='utf-8') as write_f:
 29     res = read_f.read()
 30     write_f.write(res)
 31 
 32 # 指定操作文本文件的字符编码
 33 #
 34 # 由操作系统打开文件,如果打开的是文本文件,则会涉及到字符编码问题,如果没有为open()指定编码,那么打开文本文件的默认编码很明显就是操作系统说了算
 35 # 操作系统会用自己的默认编码去打开文件,在windows下默认是gbk,linux下默认是utf-8。
 36 #
 37 # 要想保证不乱码,怎么存的就怎么取。
 38 # pycharm默认存文件时以utf-8存的,所以取的时候也应该是utf-8,不然会乱码
 39 with open('a.txt', 'r', encoding='gbk') as f:
 40     print(f.read())  # 乱码
 41 
 42 with open('a.txt', 'r', encoding='utf-8') as f:
 43     print(f.read())  # 正常展示
 44 
 45 # 文件的操作模式
 46 # 控制文件读写操作的模式
 47 # r(默认):只读
 48 # w:只写
 49 # a:只追加写
 50 
 51 # r模式的案例使用
 52 # r模式当文件不存在时报错,当文件存在时文件内指针跳到文件开头
 53 with open('a.txt', 'r', encoding='utf-8') as f:
 54     res = f.read()
 55     print(res)
 56 # 哈哈哈哈哈哈
 57 # 呵呵呵呵呵呵
 58 #
 59 # 实现用户登录功能
 60 inp_username = input('请输入你的姓名:').strip()
 61 inp_password = input('请输入你的密码').strip()
 62 
 63 with open(r'property.txt', mode='r', encoding='utf-8') as f:
 64     for line in f:
 65         u, p = line.strip('\n').split(':')
 66         if u == inp_username and p == inp_password:
 67             print('{name}登录成功'.format(name=u))
 68             break
 69         else:
 70             print('用户名或者密码错误,请重新输入')
 71 # w模式的使用
 72 # w只写模式:在文件不存在时创建空文档,文件存在时则清空文件,文件指针跑到文件开头
 73 
 74 with open('c.txt', 'w', encoding='utf-8') as f:
 75     f.write('你好')
 76     f.write('我好')
 77     f.write('大家好好')
 78     f.write('才是\n真的好')
 79 
 80 with open('c.txt', 'w', encoding='utf-8') as f:
 81     f.write('哈哈哈')
 82     f.write('呵呵呵')
 83 
 84 # 在文件不关闭的情况下,连续的写入,后写的内容一定跟在前写内容的后面。
 85 # 如果重新以w模式打开写入,则会清空文件内容
 86 #
 87 # a(只追加写模式)模式的使用:在文件不存在时创建文件,在文件存在时会将文件指针移动到文件末尾
 88 
 89 with open('d.txt','a',encoding='utf-8') as f:
 90     f.write('第一行')
 91     f.write('\n第二行')
 92 
 93 # a模式与w模式的异同:
 94 # 相同点:在打开的文件不关闭的情况下,连续的写入,新写的内容总会跟在前写的内容之后
 95 # 不同点:以a模式重新打开文件,不会清空原文件,会将文件指针移动到文件末尾。新写的内容永远写在最后。
 96 
 97 # a模式实现注册功能
 98 while True:
 99     username = input('请输入你的用户名:')
100     password = input('请输入你的密码')
101 
102     if username == 'quit':
103         break
104 
105     with open('db.txt', 'a', encoding='utf-8') as f:
106         info = '%s:%s\n' % (username, password)
107         f.write(info)
108 
109 
110 # +模式的使用
111 
112 # r+,w+,a+ 可读可写
113 
114 
115 # 控制文件读写内容的模式
116 # 大前提:tb模式均不能单独使用,必须与rwa之一结合使用
117 # t(默认的):文本模式
118 # 1、读写文件都是以字符串为单位的
119 # 2、只能针对文本文件
120 # 3、必须指定encoding参数
121 
122 # b:二进制模式
123 # 1、读写文件都是以bytes/二进制为单位的
124 # 2、可以针对所有文件
125 # 3、一定不能指定encoding参数
126 
127 # t模式的使用
128 
129 with open('test1.txt', 'rt', encoding='utf-8') as f:
130     res = f.read()
131     print(res)
132 
133 with open('test2.txt', 'wt', encoding='utf-8') as f:
134     f.write('我写了')
135     f.write('我写了')
136     f.write('我写了\n')  # 写入的必须是字符串类型
137 
138 with open('test3.txt', 'at', encoding='utf-8') as f:
139     f.write('测试哈哈哈哈')  # 写入的必须是字符串类型
140     f.write('测试哈哈哈哈')
141     f.write('测试哈哈哈哈')
142     f.write('测试哈哈哈哈')
143 
144 # t模式只能用于操作文本文件,无论读写都应该以字符串为单位,而存取硬盘本质都是二进制形式,当指定t模式时,内部
145 # 已经帮我们做了编码与解码
146 
147 # b模式的使用
148 with open('09 磁盘.mp4','rb') as f:
149     res = f.read()
150     print(res)
151     print(type(res))
152 
153 with open('wb.txt', 'wb') as f:
154     msg = '哈喽呀哈哈哈哈傻逼'
155     msg_b = msg.encode('utf-8')
156     f.write(msg_b)  # b模式写入的数据必须是bytes类型
157 
158 # 强调:b模式对比t模式
159 # 在操作纯文本文件方面,t模式帮我们省去了编码与解码的环节,b模式则需要手动编码与解码,所以t模式更加方便
160 # 针对非文本文件,如(图片、视频、音频),则b模式更加方便
161 
162 # 编写拷贝工具
163 
164 src_file = input('请输入源文件路径:').strip()
165 dest_file = input('请输入目标文件路径').strip()
166 
167 with open(r'%s' % src_file, 'rb') as read_f, open(r'%s' % dest_file, 'wb') as write_f:
168     write_f.write(read_f.read())
 
  1 # 操作文件的方法:
  2 # f.read() 读取所有内容,执行完该操作后文件指针会移动到文件末尾
  3 # f.readline() 读取一行内容,光标移动到第二行的头部
  4 # f.readlines() 读取每一行内容,存放于列表中,光标移动到文件末尾
  5 
  6 # f.read()和f.readlines都是将内容一次性读入,如果内容过大会导致内存溢出,若还想将内容全部读入内存,则必须分多次读入
  7 import time
  8 
  9 with open('xxx1.txt', 'rt', encoding='utf-8') as f:
 10     for line in f:
 11         print(line, end='')  # 以文本内容为例通过for循环每次只读取一行数据
 12 
 13 # with open('09 磁盘.mp4', 'rb') as f:
 14 #     while True:
 15 #         data = f.read(1024)
 16 #         if len(data) == 0:
 17 #             break
 18 #         print(data)
 19 
 20 with open('xxx2.txt', 'at', encoding='utf-8') as f:
 21     f.write('111\n222\n333\n')
 22     f.writelines(['aaa\n', 'bbb\n'])  # 写入多行
 23 
 24 with open('xxx3.txt', 'ab') as f:
 25     f.write('111\n222\n333\n'.encode('utf-8'))
 26     f.writelines([bytes('aaa\n'.encode('utf-8')), bytes('bbb\n'.encode('utf-8'))])
 27 
 28 # 文件是否可读:f.readable
 29 # 文件是否可写:f.writeable
 30 # 文件是否关闭:f.closed
 31 # 文件的编码:f.encoding 如果文件是以b模式打开的,则没有该属性
 32 # 立刻将文件的内容刷新到硬盘 f.flush
 33 # f.name
 34 
 35 # 主动控制文件内指针的移动
 36 # 强调:文件内指针的移动都是以Bytes为单位的,唯一例外的就是t模式下的read(n)方法,是以字符为单位的。
 37 
 38 with open('xxx4.txt', 'rt', encoding='utf-8') as f:
 39     res = f.read(3)
 40     print(res)
 41 
 42 with open('xxx4.txt', 'rb') as f:
 43     res = f.read(3)
 44     print(res.decode('utf-8'))  # 展示了一个字符我,证明我占三个字节
 45 
 46 # 之前文件内指针的移动都是由读写操作被动触发的,若想读取文件某一特定位置的数据,则需要用到f.seek()方法主动控制文件内指针的移动
 47 # f.seek(指针移动的字节数,模式控制)
 48 # 0:默认的模式,该模式代表指针移动的字节数是以文件开头为参照的
 49 # 1:该模式代表指针移动的字节数是以当前所在尾为参照的
 50 #
 51 # # 强调:0模式可以在t或者b中使用,1和2只能在t模式下使用
 52 #
 53 # # 0模式的使用的位置为参照的
 54 # 2:该模式代表指针移动的字节数是以文件末尾为参照的
 55 
 56 # 强调:0模式可以在t或者b中使用,1和2只能在b模式下使用
 57 
 58 # 0模式的使用
 59 # xxx5.txt文件内容是abc你好,abc各占一个字节,你好各占3个字节
 60 # with open('xxx5.txt','rt',encoding='utf-8') as f:
 61 #     f.seek(2,0)
 62 #     print(f.tell()) # 查看当前文件的指针距离开头位置的长度,输出结果为3
 63 #     print(f.read()) # 指针指向了c后面,则输出你好
 64 
 65 # t模式下会将读取的内容自动解码,所以必须保证读取的内容是一个完整的中文数据,否则解码失败
 66 
 67 # 1模式的使用
 68 with open('xxx6.txt', 'rb') as f:
 69     f.seek(3, 1)
 70     print(f.tell())
 71     print(f.read().decode('utf-8'))
 72     f.seek(3, 1)
 73     print(f.tell())
 74     print(f.read())
 75 
 76 # 2模式的使用
 77 with open('xxx7.txt', 'rb') as f:
 78     f.seek(0, 2)
 79     print(f.tell())
 80     f.seek(-3, 2)
 81     print(f.read().decode('utf-8'))
 82 
 83 # 实现动态查看最新一条日志的效果
 84 # 小练习:实现动态查看最新一条日志的效果
 85 # import time
 86 #
 87 # with open('access.log', mode='rb') as f:
 88 #     f.seek(0, 2)
 89 #     while True:
 90 #         line = f.readline()
 91 #         if len(line) == 0:
 92 #             # 没有内容
 93 #             time.sleep(0.5)
 94 #         else:
 95 #             print(line.decode('utf-8'), end='')
 96 
 97 # 文件的修改
 98 # 硬盘空间是无法修改的,硬盘中数据的更新都是用新内容覆盖旧内容
 99 # 内存中的数据是可以修改的
100 with open('xxx8.txt', 'r+t', encoding='utf-8') as f:
101     f.seek(9)
102     f.write('<妇女主任>')
103 
104 # 文件对应的是硬盘空间,硬盘内容不能修改对应着文件内容也不可以修改,那我们看到的文件内容可以修改是怎么实现的呢?
105 # 大致的思路是:将硬盘中文件内容读入内存,在内存中修改完毕后再覆盖会硬盘
106 
107 
108 # 文件的修改方式1:
109 # 实现思路:将文件内容一次性全部读入内存,然后在内存中修改完毕后再覆盖写回原文件
110 # 缺点:一次性读入内存,会过多的占用内存
111 # 优点:在文件修改过程中,同一份数据只有一份
112 
113 with open('xxx9.txt', 'rt', encoding='utf-8') as f:
114     res = f.read()
115 
116 with open('xxx9.txt', 'wt', encoding='utf-8') as f:
117     f.write(res.replace('egon', 'alex'))
118 
119 
120 # 文件修改方式2:
121 # 实现思路:以读的方式打开原文件,以写的方式打开一个临时文件,一行行读取原文件内容,修改完后写入临时文件,
122 # 删掉原文件,将临时文件重命名为原文件
123 # 缺点:在文件修改的过程中同一份数据存了两份
124 # 优点:一行行读取原文件内容,不会占用太多的内存
125 import os
126 with open('db1.txt','rt',encoding='utf-8') as read_f,open('.db1.txt.temp','wt',encoding='utf-8') as write_f:
127     for line in read_f:
128         write_f.write(line.replace('egon','alex'))
129 
130 os.remove('db1.txt')
131 os.rename('.db1.txt.temp','db1.txt')