文件操作

一、基本概念

1.操作系统与文件

1)操作系统
从计算机用户的角度来说,计算机操作系统体现为其提供的各项服务;从程序员的角度来说,其主要是指用户登录的界面或者接口;如果从设计人员的角度来说,就是指各式各样模块和单元之间的联系        
目前有的操作系统有windows、mac、linux等
2)文件
计算机文件是以计算机硬盘为载体存储在计算机上的信息集合。是操作系统提供给用户或者说应用程序操作硬盘的一种功能
双击文件:硬盘转,磁头读取数据
保存文件:硬盘转,磁头写入数据
# 我们在操作文件的时候其实操作的是硬盘
'''文件其实是操作系统暴露给我们可以简单快捷的操作硬盘的接口'''

2.绝对路径与相对路径

1)绝对路径
好比人所处的位置,非常详细的路径描述,无论什么人按什么位置都可以找到 
D:\Python38\include\cpython\a.txt
2)相对路径
要有一个参考,只有对应的人才可以找到
a.txt

二、文件处理

1.基本步骤

# 计算机三层体系结构:应用程序、操作系统、计算机硬件(硬盘)
1)打开文件,由应用程序向操作系统发起系统调用open(...),操作系统从对应一块硬盘空间获取文件并打开,并返回一个文件对象赋值给一个变量f
f = open('a.txt', 'r', encoding = 'utf-8') 
print(f)  # 文件对象、文件句柄
2)调用文件对象下的读/写功能,会被操作系统转化为读/写硬盘的操作
msg = f.read()
msg = f.write()
3) 向操作系统发起关闭请求,回收操作系统
f.close()

2.with语法

f = open(r'a.txt','r',encoding='utf8')  # 打开a.txt 使用变量名f指代改文件
print(f.read())
f.close()  # 回收操作系统打开的文件资源
del f  # 回收应用程序级的变量,一定发生在f.close() 之后,否则就会导致操作系统打开的文件无法关闭,白白占用资源

1)python提供了with关键字来管理上下文,自动垃圾回收,避免忘记f.close(),占用资源
with open(r'a.txt','r',encoding='utf8') as f:
    print(f.read())  # 读取文件内容
# with子代码运行结束之后会自动调用close关闭文件资源 
"""
书写形式:with open(文件路径,读写模式,编码格式) as 变量名:
             子代码块
注意:文件路径是必须的,读写模式和编码格式是可选的
"""
# 如果不指定读写模式,那么默认使用r
# 如果不指定编码格式,那么默认使用当前计算机内部默认编码
"""在中国所有的windows电脑内部默认的编码是gbk"""
with open(r'a.txt') as f:
    print(f.read())  # 读取文件内容
2)取消转义
res = r'D:\day08\a.txt'  
res1 = r'D:\day08\n.txt'  # 取消换行
res2 = r'D:\day08\t.txt'  # 取消水平制表符
res3 = r'D:\day08\v.txt'  # 取消垂直制表符
res3 = r'D:\day08\r.txt'  # 取消回车

三、文件打开

1.控制文件读写操作的模式

1) r(默认的):只读,如果文件不存在则报错,文件存在则文件指针处于文件开头
with open('a.txt', mode = 'r', encoding = 'utf-8') as f:
    res = f.read() # 会将文件的内容由硬盘全部读入内存,赋值给res
    # # print(f.read())
    # # print('='*50)
    # # print(f.read())  # 无结果,因为f已经读完,指针在最后,后面无内容
    # print(f.readable())  # out>>> True
    # print(f.writable())  # out>>> False
	
2) w:只写,如果文件不存在则建立空文档,文件存在则清空,文件指针处于文件开头
with open('b.txt', mode = 'w', encoding = 'utf-8') as f:
    # f.write("richer\n")  # \n 换行符
    # f.write("hello my friend\n")
    # f.write("come on")
    f.write("richer\nhello my friend\ncome on") # 合并上面三行代码,如过没有换行符上述三行代码将写在一行 等价于f.write("richer hello my friend come on")
    # # print(f.readable())  # out>>> False
   # # print(f.writable())  # out>>> True
	总结:w模式,在打开了文件不关的情况下,连续的write写入,新写的内容永远跟在后面
	
3) a:只追加写,如果文件不存在则创建空文档,文档存在不会清空,文件指针处于文件的末尾
with open('c.txt', mode = 'a', encoding = 'utf-8') as f:
    f.write("444\n")
    f.write("555\n")
    f.write("666\n")
    print(f.readable())  # out>>> False
    print(f.writable())  # out>>> True
总结:a模式在文件打开不关的情况下,连续write写入新的内容永远跟在后面,这一点与w模式相同
    不同点,在文件关闭后重新打开的情况下,a模式永远写在后面,而w模式则是覆盖掉原来的文件

2.控制文件读写内容的模式

'''大前提: tb模式均不能单独使用,必须与r/w/a之一结合使用'''
1) t(默认的):读写都是以字符串为单位的,只适用于文件文件,必须指定encoding参数
# 如果我们指定的文件打开模式为e/w/a,其实默认为
with open('a.txt', mode = 'rt', encoding = 'utf-8') as f:
    res = f.read()
    print(type(res))  # out>>> <class 'str'> 
with open('a.txt', mode = 'wt', encoding = 'utf-8') as f:
    s = 'abc'
    f.write(s)  # 读出的是字符串类型,则写入的也必须是字符串类型
# 强调:t 模式只能用于操作文本文件,无论读写,都应该以字符串为单位,而存取硬盘本质都是二进制的形式,当指定 t 模式时,内部帮我们做了编码与解码

2)b:读写都是以bytes为单位的,适用于所有文件,一定不能指定encoding参数
with open('1.mp4', mode = 'rb') as f:  # 可以读取视频
    res = f.read()  # 当文件小,读出的量小,使用f.read,当文件过大不要用f.read一次性读出
    print(res.decode('utf-8'))  # out>>> False 视频不能解码,视频的内容与字符编码没有关系,但是原文件是a.txt,便可以解码
with open('a.txt',mode='rb') as f:
    res = f.read()
    print(res.decode('utf-8')) # out>>> True  
with open('a.txt',mode='ab') as f:
    f.write("你好 世界".encode('utf-8'))  # 针对文本文件t模式更方便一些
案例:文件拷贝功能
# 1.不考虑文件很大的情况下
with open('1.mp4',mode='rb') as f1,open(r'D:\1111111.mp4',mode='wb') as f2:
    # res = f1.read()
    # f2.write(res)
    f2.write(f1.read())  # 将上面两行代码合并
	
# 2.考虑文件很大的情况下
# 知识储备
# with open('a.txt', mode = 'rt', encoding = 'utf-8') as f:
# 	# f.read()  # 文件太大,不要直接read,不然会导致内存直接溢出,计算机变得很卡
#     for line in f:  # 一行一行读
# 	  print(line, end = ' ')  # end 把打印自动换行符给去掉,只留文件自带换行符

# with open('1.mp4', mode = 'rb') as f:
#     for line in f:
#	  print(line)

# 具体实现
with open('1.mp4', mode = 'rb') as f1, open(r'D:\1111111.mp4, mode = 'wb') as f2:
    for line in f1:
	  f2.write(line)
其他模式:可读可写
# r+t  
# w+t
# a+t

# r+b
# w+b
# a+b

# with open('a.txt',mode='r+t',encoding='utf-8') as f:
#     print(f.readable()) # out>>> True  
#     print(f.writable()) # out>>> True  
#     print(f.read()) # out>>> True  
#     f.write("22222222222222222222\n")

# with open('a.txt',mode='w+t',encoding='utf-8') as f:
#     print(f.readable()) # out>>> True  
#     print(f.writable()) # out>>> True  

四、操作文件的方法

# a.txt :     # 三行字符
#	哈哈哈    
#	嘿嘿嘿
#	嘻嘻嘻

1.读操作

f.read()  # 读取所有内容,执行完该操作后,文件指针会移动到文件末尾
f.readline()  # 一次读取一行内容,指针移动到第二行首部,类似于for循环
f.readlines()  # 读取每一行内容,存放于列表中

with open('a.txt',mode='rt',encoding='utf-8') as f:
    # print(f.readline())  # out>>>哈哈哈   
    # print(f.readline())  # out>>>嘿嘿嘿 
    lines = f.readlines()
    print(lines)  # out>>> ['哈哈哈\n', '嘿嘿嘿\n','嘻嘻嘻\n]
	
with open('a.txt',mode='rb') as f:
    lines = f.readlines()
    print(lines)  # out>>> [b'\xb9\xfe\xb9\xfe\xb9\xfe\n',b'\xce\xfb\xce\xfb\xce\xfb\n',b'\xba\xd9\xba\xd9\xba\xd9\n']

2.写操作

with open('a.txt',mode='wt',encoding='utf-8') as f:
    f.write("111\n222\n333\n")  # 针对文本模式的写,需要自己写换行符
    # f.write("111\n222\n333\n",encode('utf-8'))  # 针对b模式的写,需要自己写换行符以及解码
    # lines = ['111\n','222\n','3333\n']
    # for line in lines:
    # f.write(line)
    f.writelines(lines)  # 传给f.writelines的类型是能被for循环循环的类型

    f.write('hello')  # 写了一次
    f.flush()  # 刷新  实时需要时用,但降低计算机运行效率
    f.writelines('hello')  # 写了五次

五、文件指针移动

'''大前提:只有t模式下的,f.read(n)中的n代表的是字符个数,除此以外,关于指针的移动,单位都是字节bytes'''
# a.txt :hello你好     # 7个字符,11个字节

1.读内容f.read()

with open('a.txt',mode='rt',encoding='utf-8') as f:
    res = f.read(3)
	print(res)  # out>>> hel
	res = f.read(6)
    print(res)  # out>>> hello你  证明t模式下read(n)都是字符
with open('a.txt', mode = 'rb') as f:
    res = read(6)
	print(res)  # 报错
	res = read(8)
	peint(res.decode('utf-8'))  # out>>> hello你

2.截断文件(删除文件内容)f.truncate()

'''是文件写操作,内容从某个位置开始到某个位置结束留下,其他的都删除'''
# r/w模式截文件都不可以,a/r+都不清文件,所以都可以截取文件内容
with open('a.txt',mode='rt',encoding='utf-8') as f:
    f.truncate(6)  # out>>> hello?

3.只动指针f.seek()

'''移动的全都是字节个数'''
# f.seek(用动的字节个数,模式)
f.seek(字节个数,0)  # 0 模式:参照文件开头移动 
f.seek(字节个数,1)  # 1 模式:参照当前指针位置移动
f.seek(字节个数,2)  # 2 模式:参照文件末尾移动,即倒着移动,通常都是负几
# ps:只有0模式可以t下使用,其中1和2模式只能在b模式下使用,但是无论在t模式还是b模式下,移动的都是字节个数
1)0 模式
with open('a.txt', mode = 'rb') as f:
    f.seek(9,0)
    f.seek(3,0)
    print(f.tell())  # out>>> 3  告诉你指针在哪
# 当前指针位置在第3个字节,因为0 模式永远参照文件开头
2)1 模式
with open('a.txt', mode = 'rb') as f:
    f.seek(3,1)
    f.seek(4,1)
# 当前指针在第7个字节,从当前位置3,移动了4个字节
3)2 模式
with open('a.txt',mode='rb') as f:
    f.seek(0,2)
    f.seek(-3,2)  
    print(f.read().decode('utf-8'))  # out>>> 好
# 当前指针位置,首先跳到文件末尾,参照文件末尾移动3个字符
航海日志
# 创建日志
access.log
# 记录日志
import time
with open('access.log', mode='at', encoding='utf8') as f:
    f.write("%s 张三 200.103.110.22 ok \n" % time.striftime("%Y-%m-%d %H:%M:%S"))
# tail 监控
with open('access.log', mode='rb') as f
    f.seek(0, 2)
    while True:
	line = f.readline()
	if len(line) == 0:
	    continue
	else:
	    print(line.encode='utf8',end=' ')  # end=' ' 去掉换行符\n

六、文件修改

'''
文件修改的原理:
    把硬盘数据读入内存,在内存修改完毕后,再覆盖回硬盘
'''
# 方案一
# 将文件内容一次性读入内存,然后在内存中修改完毕后再覆盖原文件
with open('test.txt', mode='rt', encoding='utf8') as f:
    data = f.read()
with open('test.txt', mode='wt', encoding='utf8') as f:
    f.write(data.replace('richer','RICHER'))
# 优点:在文件修改过程中同一份数据只有一份
# 缺点:会过多占用内存

# 方案二
# 以读的模式打开原文件,以写的方式打开一个临时文价,一行行读取原文件内容,修改完毕后写入临时文件,然后删掉原文件,将临时文件重命名为原文件名
import os
with open('test.txt', mode='rt', encoding='utf8') as f1,\
        open('.test.txt.swp', mode='wt', encoding='utf8') as f2:
    for line in f1:
	    f2.write(line.replace('EGON',"egon"))
os.remove('test.txt')
os.rename('.test.txt.swp', 'test.txt')
# 优点:不会占用过多的内存
# 缺点:在文件修改过程中同一份数据存了两份
posted @ 2021-06-04 17:02  Richer-J  阅读(161)  评论(0)    收藏  举报