文件的使用

文件的使用

一 文件的打开模式

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

1.1 模式r:只读(默认的模式)

#### (1) 特点:
​		文件不存在时报错,文件存在时文件指针跳到文件开头。

1.2 模式w:只写

#### (1) 特点:
​		文件不存在时创建空文件,文件存在时清空文件,并且文件指针跳到文件开头。

1.3 模式a:之追加写

#### (1) 特点:
​		文件不存在时创建空文件,文件存在时文件指针跳到文件末尾。

1.4 总结:w与a的异同

#### (1) 相同点:
​		在打开文件不关闭的情况下,连续的写入,新的内容永远跟在老的内容之后。

#### (2) 不同点:
​		重新打开文件,w模式会清空老的内容,而a模式会保留老的内容,并且指针跳到文件末尾。

1.5 案例示范:

# 示范一:注册功能
name = input('your name :').strip()
# 做合法性校验
# 1.如果输入的用户名包含特殊字符  让用户重新输入
# 2.如果输入的用户名已经存在也重新输入
pwd = input('your password :').strip()
# 做合法性校验:
# 1.密码的长度
# 2.如果密码包含特殊字符则重新输入
f_txt = open('user.txt',mode='at',encoding='utf-8')
f_txt.write('%s:%s\n' %(name,pwd))
f_txt.close()

# 示范2:登录功能
inp_name = input("your name: ").strip()
inp_pwd = input("your pwd: ").strip()

f_txt = open('user.txt',mode='rt',encoding='utf-8')
for line in f_txt:
    user,pwd=line.strip('\n').split(':')
    if inp_name == user and inp_pwd == pwd:
        print('login successful')
        break
else:
    print('user or password error')

f_txt.close()

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

2.1 模式t:文本模式(默认)

#### (1) 特点:
​		读写都是以str字符串为单位,一定要指定encoding参数。
# a.txt 'hello嘿嘿嘿哈哈哈'
f_txt = open('a.txt', mode='rt', encoding='utf-8')
res = f_txt.read()
print(res)  # hello嘿嘿嘿哈哈哈
f_txt.close()

2.2 模式b:bytes模式

#### (1) 特点:
​		读写都是以bytes为单位,一定不能指定encoding参数。
# a.txt 'hello嘿嘿嘿哈哈哈'
f_txt = open('a.txt', mode='rb')
data = f_txt.read()
# print(data, type(data))  # b'hello\xe5\x98\xbf\xe5\x98\xbf\xe5\x98\xbf\xe5\x93\x88\xe5\x93\x88\xe5\x93\x88' <class 'bytes'>
print(data.decode('utf-8'))  # hello嘿嘿嘿哈哈哈
f_txt.close()

f_txt = open('a.txt', mode='wb')
f_txt.write("张三&罗翔".encode('utf-8'))  # '张三&罗翔'覆盖原内容
f_txt.close()

2.3 上下文管理with

	-借助上下文管理,可以帮助我们不用专门去关闭文件,python解释器自动帮助我们关闭打开的文件,释放系统资源。
with open() as f_txt, open() as f1:
    f_txt.read()

2.4 补充:+模式,可读可写

	t、b模式必须与r、w、a模式联用。

	+模式必须与r、w、a模式联用:r+、w+、a+
### 2.4.1 rt与r+t比较:

1) rt:只读文本模式(默认的模式,如果不指定模式,就会默认此模式) 
# a.txt 'hello嘿嘿嘿哈哈哈'
with open('a.txt', mode='rt', encoding='utf-8') as f_txt:
    res = f_txt.tell()
    res1 = f_txt.read()
    res2 = f_txt.tell()
    print(res, res1, res2)  # 0 hello嘿嘿嘿哈哈哈 23

2) r+t:可读可写文本模式,开头就写类似wt模式,对原内容进行覆盖,可能会造成乱码。在读完内容之后,文件指针移动到末尾,写入内容之后,如三个汉字,会返回3个字符的长度,此时文件指针仍在末尾,无法读取出有效内容,文件指针在写入三个汉字后,文件指针移动9个字节。
# a.txt 'hello嘿嘿嘿哈哈哈'
with open('a.txt', mode='r+t', encoding='utf-8') as f_txt:
    res = f_txt.tell()
    # res0 = f_txt.write('嚯嚯嚯')  # 必须读完再写,否则会覆盖原来的内容,造成乱码
    res1 = f_txt.read()
    res2 = f_txt.tell()
    res3 = f_txt.write('嚯嚯嚯')
    res4 = f_txt.read()
    res5 = f_txt.tell()
    print(res, res1, res2, res3, res4, res5)  # 0 hello嘿嘿嘿哈哈哈 23 3  32

### 2.4.2 wt与w+t比较:

1) wt:只写文本模式,不可读,报错后文件清空,也没有执行写的操作
# a.txt 'hello嘿嘿嘿哈哈哈'
with open('a.txt', mode='wt', encoding='utf-8') as f_txt:
    res = f_txt.tell()
    # res0 = f_txt.read()  # io.UnsupportedOperation: not readable
    res1 = f_txt.write('hello哈哈哈')
    res2 = f_txt.tell()
    print(res, res1, res2)  # 0 8 14
                            #开始指针位置,写入字符个数,写入之后指针位置

2) w+t:可读可写文本模式,但是无论文件指针在何处,都无法读取出内容
# a.txt 'hello嘿嘿嘿哈哈哈'
with open('a.txt', mode='w+t', encoding='utf-8') as f_txt:
    res = f_txt.tell()
    res0 = f_txt.read()
    res1 = f_txt.write('hello哈哈哈')
    res2 = f_txt.read()
    res3 = f_txt.tell()
    print(res, res0, res1, res2, res3)  # 0  8  14
### 2.4.3 at与a+t比较:

1) at:只追加写文本模式
# a.txt 'hello嘿嘿嘿哈哈哈'
with open('a.txt', mode='at', encoding='utf-8') as f_txt:
    res = f_txt.tell()
    # res0 = f_txt.read()  # io.UnsupportedOperation: not readable
    res1 = f_txt.write('hello哈哈哈')
    res2 = f_txt.tell()
    print(res, res1, res2)  # 23 8 37
# 最新文件内容:hello嘿嘿嘿哈哈哈hello哈哈哈

2) a+t:可读可写文本模式,写只追加
# a.txt 'hello嘿嘿嘿哈哈哈'
with open('a.txt', mode='a+t', encoding='utf-8') as f_txt:
    res = f_txt.tell()
    f_txt.seek(0, 0)
    res0 = f_txt.read()
    f_txt.seek(0, 0)
    res1 = f_txt.write('hello哈哈哈')
    res2 = f_txt.tell()
    print(res, res0, res1, res2)  # 23 hello嘿嘿嘿哈哈哈 8 37
# 最新文件内容:hello嘿嘿嘿哈哈哈hello哈哈哈

二 文件操作的其他方法

1 读相关的方法

1) f.read()  # 读取所有内容,执行完该操作后,文件指针会移动到文件末尾。
# read(n)注意:在t模式下,括号内的参数n值得是字符数,b模式下指的是字节数!

2) f.readline()  # 从当前指针位置开始读取一行内容,光标移动到第二行首部

3) f.readlines()  # 读取每一行内容,存放于列表中
# 强调:
# f.read()与f.readlines()都是将内容一次性读入内容,如果内容过大会导致内存溢出,若还想将内容全读入内存,则必须分多次读入,有两种实现方式:
# 方式一
with open('a.txt',mode='rt',encoding='utf-8') as f:
    for line in f:
        print(line) # 同一时刻只读入一行内容到内存中

# 方式二
with open('1.mp4',mode='rb') as f:
    while True:
        data=f.read(1024) # 同一时刻只读入1024个Bytes到内存中
        if len(data) == 0:
            break
        print(data)
4) f.readable()  # 判断文件是否可读

2 写相关的方法

1) f.write('1111\n222\n')  # 针对文本模式的写,需要自己写换行符
f.write('1111\n222\n'.encode('utf-8'))  # 针对b模式的写,需要自己写换行符

2) f.writelines(['333\n','444\n'])  # 文件模式
f.writelines([bytes('333\n',encoding='utf-8'),'444\n'.encode('utf-8')]) #b模式
3) f.writable()  # 文件是否可写

4) f.flush()  # 立刻将文件内容从内存刷到硬盘

3 其他方法

1) f.closed  # 文件是否关闭

2) f.encoding  # 获取文件的编码格式,如果文件打开模式为b,则没有该属性

3) f.name  # 获取文件名

4) f.truncate(n)  # 从文件开头往后数n个字节保留下来,其余全部删除
				  # 如果n不指定,则从文件开头往后数指针当前所在的位置,其余全部删除

三 控制文件内指针移动

1 控制文件指针移动的单位

1.1 控制文件指针移动的单位都是字节;

1.2例外情况:t模式下的read(n),代表的是n个字符,此外代表的全都是字节。

with open('f.txt', mode='rt', encoding='utf-8') as f:
    data = f.read(6)  # 6个字符
    print(data)

with open('f.txt', mode='rb') as f:
    # data=f.read(6) # 6个字节
    data = f.read(8)  # 8个字节
    print(data.decode('utf-8'))

1.3f.seek(offset,whence)

f.seek(n,模式) # n代表的移动的字节个数

2 控制文件指针移动的三种模式 0/1/2

#### 1.模式0:
参照文件的开头开始移动(只有0模式可以在t模式下使用,1、2模式只能在b模式下使用) 
# a.txt用utf-8编码,内容如下(abc各占1个字节,中文“你好”各占3个字节) 
abc你好

# 0模式的使用
with open('a.txt',mode='rt',encoding='utf-8') as f:
    f.seek(3,0)     # 参照文件开头移动了3个字节
    print(f.tell()) # 查看当前文件指针距离文件开头的位置,输出结果为3
    print(f.read()) # 从第3个字节的位置读到文件末尾,输出结果为:你好
    # 注意:由于在t模式下,会将读取的内容自动解码,所以必须保证读取的内容是一个完整中文数据,否则解码失败

with open('a.txt',mode='rb') as f:
    f.seek(6,0)
    print(f.read().decode('utf-8')) #输出结果为: 好
#### 2.模式1:
参照指针当前所在的位置(只能在b模式下使用) 
# 1模式的使用
with open('a.txt',mode='rb') as f:
    f.seek(3,1) # 从当前位置往后移动3个字节,而此时的当前位置就是文件开头
    print(f.tell()) # 输出结果为:3
    f.seek(4,1)     # 从当前位置往后移动4个字节,而此时的当前位置为3
    print(f.tell()) # 输出结果为:7
#### 3.模式2:
参照文件末尾的位置(只能在b模式下使用) 
# a.txt用utf-8编码,内容如下(abc各占1个字节,中文“你好”各占3个字节) 
abc你好

# 2模式的使用
with open('a.txt',mode='rb') as f:
    f.seek(0,2)     # 参照文件末尾移动0个字节,即直接跳到文件末尾
    print(f.tell()) # 输出结果为:9
    f.seek(-3,2)     # 参照文件末尾往前移动了3个字节
    print(f.read().decode('utf-8')) # 输出结果为:好

3 使用案例:模拟程序记录日志的功能

# 模拟记录日志
import time
for i in range(10000):
    with open('access.log', mode='at', encoding='utf-8') as f:
        t = time.strftime('%Y-%m-%d %H:%M:%S')
        content = '张三给李四转了%s毛钱' %i
        
        msg = f'{t} {content}\n'
        f.write(msg)
    time.sleep(3)
# 监控日志
import time
with open('access.log', mode='rb') as f:
    f.seek(0,2)
    while True:
        line = f.readline()
        if len(line) == 0:
            time.sleep(0.3)
        else:
            print(line.decode('utf-8'), end='')

四 文件修改的两种方式

	-由于硬盘中文件的都是用新内容去覆盖旧内容,而内存中文件是可以实时修改的,因此我们有两种方法进行文件的修改:

1 方式一:覆盖法

#### 1.1 步骤:
(1) 先将硬盘中文件的内容全部读入内存,然后在内存中修改完毕得到一个修改好的结果;

(2) 将修改好的结果覆盖回原文件。
# 代码示例:
with open('a.txt', mode='rt', encoding='utf-8') as f:
    data = f.read().replace('old_data', 'new_data')
with open('a.txt', mode='wt', encoding='utf-8')as f:
    f.write(data)    
#### 1.2 优缺点:
优点是不耗费硬盘,缺点是耗费内存。

2 方式二:替换法

#### 2.1 步骤:
(1) 循环读取硬盘中文件的内容,一行行修改内容并逐行写入一个新的临时文件;

(2) 删除源文件,将临时文件命名为源文件相同的名字。
# 代码示例:
import os
with open('a.txt', mode='rt', encoding='utf-8') as f_read, open('.a.txt.swp', mode='wt', encoding='utf-8') as f_write:
    for line in f_read:
        res = line.replace('old_data', 'new_data')
        f_write.write(res)
#### 2.2 优缺点:
优点是不耗费内存,缺点是耗费硬盘。
posted @ 2020-03-10 18:23  越关山  阅读(310)  评论(0)    收藏  举报