1. 文件操作

文件就是计算机的操作系统虚拟给用户操作硬盘的一个接口。我们都知道,内存和硬盘都是存储数据的,但是内存的数据易丢失,当我们需要在下次启动计算机的时候还能够看到我们写的东西,就必须要把我们的东西写入到硬盘中,这也就是文件存在的意义。

操作文件的三个步骤
1. 打开文件得到一个文件句柄
2. 通过这个文件句柄来对文件进行我们想要的操作
3. 向操作系统发送关闭指令,回收操作系统资源

2. 打开文件的模式

打开文件的模式总共有五种,三种纯净模式,r, w,    a,  以及控制打开文件格式的两种模式: t, b 

'''
控制文件格式的两种模式必须和三种纯净模式一块进行使用,不能单独使用:
三种纯净模式:
    r: 只读,文件指针在默认在开头,文件不存在就跑出异常
    w: 只写,文件指针也在开头,文件不存在就创建,存在就清空内容写入
    a: 追加写入,文件指针在结尾,文件不存在就创建,存在就追加写入
控制文件格式的两种模式:
    t:文本格式:只能操作文本文件,在这样的格式下一般需要指定处理文本的编码方式,否则无法跨平台进行使用
   b: 二进制格式: 可以操作所有的文件,因此存储就是用的字节,所以在此模式下不能指定编码方式 

'''

(1). r只读模式:在文件不存在的时候报错,文件存在指针直接跳到开头

简单的打开文件的方式:但是不建议这样写,因为如果没有指定mode和编码方式,采取的都是默认的,mode为rt,编码方式为操作系统默认的编码,如果一旦出现了跨平台的操作,就会出现乱码的问题!

with open('user_gbk') as f:
    print(f.readline(11))

# 无论打开什么文件,都建议指定模式和编码方式
with open('user_gbk', mode='rt', encoding='gbk') as f:
  print(f.read())

文件读取的两种模式之 【rt】模式

# 以rt模式打开的建议指定上字符编码,单位为字符  
with open('user_utf-8', 'rt', encoding='utf-8') as f:
# 把一个文件全部的内容读取出来,返回一个字符串,一般不建议这样读文件,容易撑爆内存 # data = f.read() # print(data, type(data), len(data)) # 读取当前指针所在行的值,传递的参数代表的是读取几个字符 data = f.readline(4) print(data) # 把每一行的值转换成一个字符串,最后返回一个列表 data = f.readlines() print(data)

文件读取的两种模式之 【rb】模式

# 以rb模式打开的不能指定字符编码,单位都是字节
with open('user_utf-8', 'rb') as f:
#     for line in f:
#         print(len(line))
    # 把一个文件全部的内容读取出来,返回一个bytes类型,一般不建议这样读文件,容易撑爆内存
    # 如果我们想查看内容,就用写入文件编码方式解码
    # data = f.read()
    # print(data, type(data), len(data), data.decode('utf-8'))
    # 读取当前指针所在行的值,传递的参数代表的是读取几个字节
    data = f.readline(3)
    print(data)
    # 把每一行的值转换成bytes类型,最后返回一个列表
    data = f.readlines()
    print(data)

例题:以rb的形式读取一张图片

with open('ceshi.png', 'rb') as f:
    data = f.read()
    print(data)

 (2)r只写模式:在文件不存在的时候创建,文件存在指针直接跳到开头,覆盖写入文件

文件写入的两种模式之 【wt】模式

# wt的模式写入的必须是字符串
with open('user_utf-8', 'wt', encoding='utf-8') as f:
    f.write('中国你好!'.encode('utf-8'))
    line = ['111', '222', '444']
    # 下面这两种方法是一样的
    for i in line:
        f.write(i)
    f.writelines(line)

 文件写入的两种模式之 【wb】模式

# 写入的是字节,因此当我们在写入的时候创建了
# 一个字符串需要先进行编码才能够进行写入
with open('user_utf-8', 'wb') as f:
    f.write('中国你好好!'.encode('utf-8'))

(3).a只写模式:在文件不存在的时候创建,文件存在指针直接跳到文件结尾,追加写入文件,和w的区别就是一个是清空写入,一个是追加写入,其他的都是一样的。

例题:做一个简单的拷贝文件的工具

# 拷贝文件的小工具
src_file = input('源文件路径>>').strip()
dst_file = input('目的文件路径>>').strip()
with open(src_file, 'rb') as read_f, open(dst_file, 'wb') as write_f:
    for line in read_f:
        write_f.write(line)

3. 文件内光标的移动

光标的移动在【rt】模式下是是字符为单位的,但是在【rb】的形式下是以字节为单位的

# rt模式 读的是字符
with open('user_utf-8', 'rt', encoding='utf-8') as f:
    data = f.read(3)
    print(data)

# rb模式,读的是字节,如果想显示出原始的字符,得先进行解码
with open('user_gbk', 'rb') as f:
    # data = f.read(3)
    # b'\xe4\xb8\xad'
    data = f.read(2)
    print(data, data.decode('gbk'))

控制文件指针移动的方法:

f.seek(参数一, 参数二)

参数一: 指的是移动的字节数
参数二:0 模式是默认模式,在任何的打开方式下都可以使用,但是1,和2 只能在b模式下才可以进行使用
    0:文件指针以文件开头为参照移动【参数一】个字节数,移动的字节数不能为负
    1: 文件指针以当前指针所在位置为参照移动【参数一】个字节数, 负数为左,正数为右
    2: 文件指针以文件末尾为参照移动【参数一】个字节数

f.tell()
  查看当前指针离文件头部的字节数

0模式:

# f.seek的0模式,f.seek的指针都是以字节形式移动的
# 在我们人为操作移动的过程中,不能把一个字符给拆分开
# 否则在打印的时候会报错
# rt模式
with open('user_utf-8', 'rt', encoding='utf-8') as f:
    f.read()
    f.seek(3, 0)
    print(f.tell())
    print(f.read())

# rb模式
with open('user_utf-8', 'rb') as f:
    f.seek(3, 0)
    print(f.tell())
    print(f.read().decode('utf-8'))

1 模式

# f.seek的1模式,
# 1.只能在b模式下进行使用
# 2.偏移量可负可正,负为左,正为右
# 3.指针移动不能拆分字符,否则在解码的时候会报错
with open('user_utf-8', 'rb') as f:
    f.read()
    f.seek(-3, 1)
    print(f.read().decode('utf-8'))

2 模式

# f.seek的2模式
# 1. 只能在b模式下使用
# 2. 偏移量可正可负,正返回为空,负代表指针移动
# 3.指针移动不能拆分字符,否则在解码的时候会报错
with open('user_utf-8', 'rb') as f:
    f.seek(-3, 2)
    print(f.read().decode('utf-8'))

例题:tail -f access.log  模拟当前命令

command = input('请输入命令(Q退出)>>').strip()
while True:
    try:
        if command.upper() == 'Q':
            break
        if command.split()[0] == 'tail' and command.split()[1] == '-f':
            # 输入的命令没有错误,获取文件名
            file_path = command.split()[2]
            print(file_path)
            with open(file_path, 'rb') as f:
                # 移动指针到尾部
                f.seek(0, 2)
                while True:
                    line = f.readline()
                    # 如果没有文件导入,就继续循环
                    if len(line) == 0:
                        continue
                    else:
                        # 如果有文件导入就写入文件
                        print(line.decode('utf-8'))
        else:
            print('usage: tail -f file_path!')
    except:
        print('usage: tail -f file_path!')

4. 文件的修改

   文件就是计算机的操作系统给我们映射的一块硬盘空间。对于硬盘而言,是没有办法修改的,我们对于硬盘的操作也只能是覆盖写入,因此文件也是不能修改的。但是我们会发现,我们每次打开文件的是可以对其进行的修改的,这究竟是怎么回事呢?是因为内存。我们的数据在硬盘上是没有办法修改,但是在内存中确是可以进行修改的,因此我们通常所说的文件修改其实指的就是内存的修改。通过内存修改完成之后重新写入硬盘中的。

文件修改的两种方式:

1. 把文件全部加载到内存中,然后在内存中修改我们的数据,之后统一的写入文件中
  优点:在文件修改过程中同一份数据只有一份
  缺点:会占用过多的内存
2. 把文件一行一行的加载到内存中,一行行的修改之后写入到一个新的文件,当修改完成之后,删除源文件,然后把新的文件名字改成源文件的名字。
  优点:不会占用过多的内存
  缺点:在文件修改过程中,会有两份数据存在硬盘中。

验证硬盘里的数据是不能修改的:

文件内容:

你好,啊slegeg
我好
大家好
# 文件内容:
'''
你好,啊slegega
我好
大家好
'''

with open('user_utf-8', 'r+t', encoding='utf-8') as f:
    # 移动指针到第一行的【啊】后面
    f.seek(12, 0)
    # 写入【中国好】三个字
    # 如果硬盘数据能够进行修改第一行一概出现:你好,啊中国好slegega
    # 如果硬盘不能改只能覆盖,应该出现:你好,啊中国好我好(因为把这一行后面的换行符也去掉了)
    f.write('中国好')

文件的修改方法:

文件内容:

kevin is dsb
dsb is kevin
alex is kevin 

第一种方式的把kevin全部改成SB

# 内容全部加载到内存
with open('a.txt', 'rt', encoding='utf-8') as f:
    res = f.read().replace('kevin', 'SB')

# 将修改的数据重新写入文件中
with open('a.txt', 'wt', encoding='utf-8') as f:
    f.write(res)

第二种方式把所有‘SB'全部改成kevin

# 首先打开以rt得方式打开源文件,然后以wt的形式打开一个新文件
with open('a.txt', 'rt', encoding='utf-8') as read_file,\
        open('.a.txt.swap', 'wt', encoding='utf-8') as write_file:
    # 修改一个值并写入到一个新的文件中
    for line in read_file:
        res = line.replace('SB', 'kevin')
        write_file.write(res)
import os
os.remove('a.txt')
os.rename('.a.txt.swap', 'a.txt')
10-13 12:12