一、 可读可写:
# r+t  :可读可写 一打开光标就在开始位置
              直接写将导致原始数据被覆盖
# w+t:可读可写 一打开光标就在开始位置
             会把原始全都清空了
             要使用可读可写模式 首先要保证 你知道数据是如何编码的
# a+t :  可读可写 一打开光标就在文件末尾

with open('a.txt',mode='r+t',encoding='utf-8') as f:
    print(f.readable())   #判断是否可读
    print(f.writable())    #判断是否可写
    msg=f.readline()         #只读一行
    print(msg)
    f.write('xxxxxxxxxxx\n')
----------------------------------------------------
True
True

a.txt

xxxxxxxxxxx
 \n (回车)

二、控制文件内的指针移动

# 文件内指针移动,只有t模式下的read(n),n代表的字符的个数
# 除此以外文件内指针的移动都是以字节为单位

with open('a.txt',mode='rt',encoding='utf-8') as f:
    msg=f.read(1)      #()不写全部读
    print(msg)
-------------------------------
x
# 使用b模式打开后转成文本模式的使用decode解码(指定编码格式)
with open('a.txt',mode='rb') as f:
    msg=f.read(3)
    print(msg.decode('utf-8'))
-------------------------------------------
xxx

a.txt

xxxxxxxxxxx
   (\n 回车)

# f.seek(offset,whence)有两个参数:
# offset: 代表控制指针移动的字节数
# whence: 代表参照什么位置进行移动
#        whence = 0: 参照文件开头(默认的),特殊???,可以在t和b模式下使用
#        whence = 1: 参照当前所在的位置,必须在b模式下用
#        whence = 2: 参照文件末尾,必须在b模式下用

a.txt

123456789
  1. py

with open('a.txt',mode='rt',encoding='utf-8') as f:
    f.seek(6,0)                 #从文件开头,print 时会读到下一个
    msg=f.read(1)
    print(msg)
-------------------------------------------------------------
7 

with open('a.txt',mode='rb') as f:
    f.seek(3,0)
    msg=f.read(3)
    print(msg.decode('utf-8'))   
-------------------------------------------
456 

with open('a.txt',mode='rb') as f:       
# utf-8中 b:模式是读:“字节”(3个字节是一个字符) t:模式是字符(一个汉字)
    msg=f.read(3)
    print(msg.decode('utf-8'))
    print(f.tell())
    # f.seek(6,0)
    f.seek(3,1)
    msg1=f.read(3)
    print(msg1.decode('utf-8'))  
---------------------------------------------------
123
3
789
# 接上面 例子: 
with open("a.txt",'rb')as f:
    f.seek(8,0)
    print(f.read(1).decode('utf-8'))      
    # utf-8中 f.read("字节") b:模式是读:“字节”(3个字节是一个字符) t:模式是字符(一个汉字)
    # 取字符e 
    # 取到第2个t
    # 如果一行都是(utf-8)中文,(b模式)都是按照3个字节是一个字符来算,若有中文也有英文,f.read(1) 应该按照一个字节取,中文还是算3个,若全是中文应该是f.read(3)
    # 因为3个字节一个中文

a.txt

×××
123456789
jkljkljhkljhkl

1.py

with open('a.txt',mode='rb') as f:
    msg=f.read(3)
    print(msg.decode('utf-8'))
    print(f.tell())     #统计文件的字符数,utf-8中 一个中文字符占3个字节数
    # f.seek(6,0)       # #0模式,是0模式往后移动的位置再在当前光标处继续移动 字节(b模式的话)。
    f.seek(3,1)         #如果最开始用1模式的话,是与0模式效果一样,因为都是从光标开头出开始
    msg1=f.read(3)
    print(msg1.decode('utf-8'))
----------------------------------------------
中
3
人
  1. py

with open('a.txt',mode='rb') as f:
    # f.seek(0,2)
    # print(f.tell())
    f.seek(-3,2)        # 2模式前面必须是负数,因为正数的话是往后取值(2模式本来就是文件末尾)
    msg=f.read(3)
    print(msg.decode('utf-8'))
--------------------------------------
hkl
with open('access.log',mode='rb') as f:
    f.seek(0,2) # 当前位置是147bytes
    while True:
        line=f.readline() # 当前位置是196bytes
        # print(f.tell())
        if len(line) == 0:
            # 没有新的一行内容追加进来
            pass
        else:
            # 有新的一行内容追加进来
            print(line.decode('utf-8'),end='')
with open('access.log',mode='rb') as f:
    f.seek(0,2) # 当前位置是147bytes
    while True:
        line=f.readline() # 当前位置是196bytes
        if len(line) != 0:
            print(line.decode('utf-8'),end='')
with open('a.txt',mode='r+t',encoding='utf-8') as f:
    f.truncate(6)

a.txt (旧)

×××

a.txt (新)

中华
import time

with open('access.log','at',encoding='utf-8') as f:
    f.write('%s alex给egon转账了1个亿\n' %time.strftime('%Y-%m-%d %H:%M:%S'))


三、文件修改的两种方式

# 修改文件的方式一:
# 1 将文件内容由硬盘全部读入内存
# 2 在内存中完成修改
# 3 将内存中修改后的结果覆盖写回硬盘

a.txt

alex
  1. py (将文件a.txt中的alex修改成为"dsb")

with open('a.txt',mode='rt',encoding='utf-8') as f:
    all_data=f.read()
print(all_data,type(all_data))
with open('a.txt',mode='wt',encoding='utf-8') as f:
    f.write(all_data.replace('alex','dsb'))

# 修改文件的方式二:  (将文件a.txt中的"alex"修改成为"dsb")

# 1 以读的方式打开源文件,以写的方式打开一个临时文件
# 2 从源文件中每读一样内容修改完毕后写入临时文件,直到源文件读取完毕
# 3 删掉源文件,将临时文件重命名为源文件名

import os
with open('a.txt',mode='rt',encoding='utf-8') as read_f,open('.a.txt.swap',mode='wt',encoding='utf-8') as write_f:
    for line in read_f:
        write_f.write(line.replace('alex','dsb'))
os.remove('a.txt')
os.rename('.a.txt.swap','a.txt')

# 方式一:
# 优点: 在文件修改的过程中硬盘上始终一份数据
# 缺点: 占用内存过多,不适用于大文件


# 方式二:
# 优点: 同一时刻在内存中只存在源文件的一行内容,不会过多地占用内存
# 缺点: 在文件修改的过程中会出现源文件与临时文件共存,硬盘上同一时刻会有两份数据,即在修改的过程中会过多的占用硬盘,


# 把列表写入到文件中

# 将列表转成字符,然后再写入到文件中

l=[1,2,3,'a','b','c','d']
with open ("c.txt",'w+t',encoding='utf-8') as f:
    f.write(str(l))

c.txt

[1, 2, 3, 'a', 'b', 'c', 'd']