Python小白学习之路(二十)—【打开文件的模式二】【文件的其他操作】

打开文件的模式(二)

对于非文本文件,我们只能使用b模式,"b"表示以字节的方式操作
(而所有文件也都是以字节的形式存储的,使用这种模式无需考虑文本文件的字符编码、图片文件的jgp格式、视频文件的avi格式)

rb:    以字节方式读文件
wb:  以字节方式写文件
ab:   以字节方式追加文件

注:以b方式打开时,读取到的内容是字节类型,写入时也需要提供字节类型,所以不能指定编码

1. rb

#错误举例
f = open (‘test1.py‘, ‘rb‘, encoding = ‘utf -8‘)
data = f.read()
print(data)
f.close()

#执行结果:
报错
f = open (‘test1.py‘, ‘rb‘, encoding = ‘utf-8‘)
ValueError: binary mode doesn‘t take an encoding argument

(以b方式打开时,因为读取到的内容是字节类型,所以不能指定编码方式,否则会报错)
#正确
f = open (‘test1.py‘, ‘rb‘)
data = f.read()
print(data)
f.close()

#执行结果:
b"‘hello‘\r\n‘\xe5\xb0\x8f\xe7\x81\xab\xe9\x94\x85‘\r\n‘666‘"

test1.py中的内容如下:

‘hello‘
‘小火锅‘
‘666‘

分析该程序执行结果:

1. python在windows操作系统下,换行符为在windows操作系统下,换行符为 \r\n
2. ‘字符串’-------encode-------》bytes
     bytes---------decode-------》‘字符串’

所以,我们想让执行结果为字符串,可在print时做decode处理

f = open (‘test1.py‘, ‘rb‘)
data = f.read()
print(data.decode(‘utf-8‘))
f.close()

#执行结果:
‘hello‘
‘小火锅‘
‘666‘

2. wb

#错误举例

f = open (‘test1.py‘, ‘wb‘)
f.write(‘hello‘)
f.close()

#执行结果:

TypeError: a bytes-like object is required, not ‘str‘

(以b方式写入时需要提供字节类型,所以不能写入字符串类型)
#正确

f = open (‘test1.py‘, ‘wb‘)
f.write(bytes(‘hello\n小火锅‘, encoding = ‘utf-8‘ ))
f.close()

3. ab

#举例
f = open (‘test1.py‘, ‘ab‘)
f.write(bytes(‘hello\n小火锅\n‘, encoding = ‘utf-8‘ ))
f.close()

关于文件的其他操作介绍

1. .encoding 读取文件打开时后的编码方式(即open时指定的编码方式)

#举例

f = open (‘test1.py‘, ‘w‘, encoding = ‘GB2312‘)
f.close()
print(f.encoding)

#执行结果:

GB2312

2. .closed 确定文件是否关闭

#举例

f = open (‘test1.py‘, ‘w‘, encoding = ‘utf-8‘)
f.close()
print(f.closed)

#执行结果:

True

3. .flush 刷新操作(将文件内容从内存刷到硬盘)

4. .tell 读取光标所在位置

补充:文件内光标移动

一: read(3):

   1. 文件打开方式为文本模式时,代表读取3个字符

   2. 文件打开方式为b模式时,代表读取3个字节

二: 其余的文件内光标移动都是以字节为单位如seek,tell,truncate

test1中的内容
aaa
小火锅
666

#举例
f = open (‘test1.py‘, ‘r‘, encoding = ‘utf-8‘)
print(f.tell())
f.readline()
print(f.tell())
f.readline()
print(f.tell())
f.close()

#执行结果:
0
5
16
#结果分析:
第一个tell判断光标位置时候,光标在文件开头,即在位置0
读取了一行之后,光标跑到文件第二行开头,但是在Windows操作系统,换行符为 \r\n,占两个字节,而且tell光标移动以字节为单位,所以光标位置为 5
读取了第二行之后,光标跑到了文件第三行开头,光标经历了三个汉字和换行符,在编码方式为 utf-8 时,走过了3*3+2=11个字节,所以光标位置为 16

5. .seek 控制光标的移动

#举例
f = open (‘test1.py‘, ‘r‘, encoding = ‘utf-8‘)
f.seek(2) #光标从默认位置0开始,往后移动两个字节
data = f.read()
print(data) #打印光标后的内容
f.close()

#执行结果:
a
小火锅
666

如果,我将test1.py的内容改为

小火锅
aaa
666

再次执行上述程序

#报错:UnicodeDecodeError: ‘utf-8‘ codec can‘t decode byte 0x8f in position 0: invalid start byte

原因:一个汉字在utf-8编码方式为3个字节,seek(2)移动两个字节,难道有神奇的功能将汉字劈开嘛,所以肯定会报错啊!

关于seek的一些补充:

seek有三种模式,分别为

  • 0模式 默认从0开始(不用指定)
  • 1模式 从上次相对位置开始
  • 2模式 从文件末尾开始seek(第一个参数需要为负数)
举例:
f = open (‘test1.py‘, ‘r‘, encoding = ‘utf-8‘)
f.seek(3)
print(f.tell())
f.seek(9)
print(f.tell())
f.close()

#执行结果
3
9
f = open (‘test1.py‘, ‘rb‘)
f.seek(3,1)
print(f.tell())
f.seek(10,1)
print(f.tell())
f.close()

#执行结果
3
13
f = open (‘test1.py‘, ‘rb‘)
f.seek(-3,2) #seek 在模式 2 时,第一个参数为负数
print(f.tell())
print(f.read())
f.close()

#执行结果
18
b‘6\r\n‘

任务:应用:打开一个日志文件,并且读取最新日志(核心:倒着读文件内容)

日志文件内容如下:
2018/11/20 aaa 上网听歌
2018/11/20 bbb 上网网购
2018/11/20 ccc 上网学习

#方法一
f = open(‘日志文件‘, ‘rb‘)
data = f.readlines() #将日志文件的内容以列表形式读到内存中
print(data[-1].decode(‘utf-8‘)) #以切片方式读取列表中最后一个元素,即文件最后一行内容

#执行结果
2018/11/20 ccc 上网学习
#方法二
f = open(‘日志文件‘, ‘rb‘)
for i in f: #文件循环方式
    offs = -10 #设置初始偏移量
    while True: #设置一个死循环来读取文件的最后一行内容,读取到break
        f.seek(offs, 2) #seek模式2,光标倒着移动
        data = f.readlines() #以列表形式读取光标后的内容
        if len(data) > 1: #如果该列表长度大于1,说明光标移动到最后一行之前,最后一行内容已被读出,break,反则最后一行内容还未全部读出,将偏移量扩大,直到独处最后一行全部内容
          print(‘文件最后一行:%s‘%(data[-1].decode(‘utf-8‘)))
          break
        offs *= 2

#执行结果
文件最后一行:2018/11/20 ccc 上网学习                        

方法一看着简单,但是方法一需要将日志文件的内容一列表形式全部读到内存中,占用较多内存
方法二的思想就是我用最后一行内容,我倒着读,只关注我想得到的信息

6. .truncate 截取文件内容(实质为文件内容的改写,所以在 open 文件时,需要设置正确的打开文件的模式)

举例:

f = open(‘日志文件‘, ‘r+‘,encoding = ‘utf-8‘)
data = f.truncate(8)
print(data)

注意:

  • 打开方式不可以是r(报错,实质为文件的改写)
  • 打开方式不可以是w w+(这两个模式将内容全部删除,所以截取不到任何内容)

原文地址:https://www.cnblogs.com/guoruxin/p/10008904.html

时间: 2024-08-27 09:23:18

Python小白学习之路(二十)—【打开文件的模式二】【文件的其他操作】的相关文章

Python小白学习之路(十六)—【内置函数一】

将68个内置函数按照其功能分为了10类,分别是: 数学运算(7个) abs()   divmod()  max()  min()  pow()  round()  sum() 类型转换(24个) bool()  int()  float()  complex()  str()  bytearray() bytes() memoryview() ord() chr() bin() oct() hex() tuple() list() dict() set() frozenset( ) enumer

Python小白学习之路(二十二)—【生成器】

一.什么是生成器? 生成器可以理解成是一种数据类型,特殊地是生成器可以自动实现迭代器协议其他的数据类型需要调用自己内置的__iter__方法所以换种说法,生成器就是可迭代对象 !回忆:很重要的迭代器协议 对象必须提供一个 next 方法,执行该方法要么返回迭代中的下一项,要么就引起一个Stoplteration异常,以终止迭代(只能往后走不能往前退) 二.生成器的分类(两类) python中生成器的表现形式 python中提供生成器的方式 一类是生成器函数:另一类是生成器表达式 第一类:关于生成

Python小白学习之路(四)——第一次练习题

写在前面: 今天下雪了呢!连着两天都没有更新学习记录. 我没有偷懒呢.做了一天的练习题,昨天学的内容还没总结完,太累了就回去睡觉了 连续一周早起,强大的内心也无法支撑我疲惫的身体 今天早起做了整理.加油哦(贵在坚持,一定要好好坚持下去) 1.执行 Python 脚本的两种方式 (1)进入python解释器,等待用户实时输入(2)python.exe + 执行文件的路径 2.简述位.字节的关系 1字节 = 8位 3.简述 ASCII,Unicode,utf-8.gbk 的关系 ASCII是最早美国

Python小白学习之路—变量、字符编码、字符拼接

变量命名规则: (1)变量名只能是字母,数字,下划线的任意组合. ex:_amber_666NAme (2)关键字不能声明为变量名 ex:['and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'exec', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'not'

Python小白学习之路—while、for循环、运算

Python里面的循环跟其他语言里的循环基本一致,只是书写格式不同. 1.for循环: for [循环条件]:[循环语句] 满足循环条件,则执行循环语句,执行一次判断一次,不满足则结束循环. 简单的循环: in range() 表示在什么范围里 1 # 循环 自动累计加一 2 # 一个参数代表从0开始到多少 3 for i in range(10): 4 print("One:",i) 5 # 两个参数代表范围 6 for i in range(0,5): 7 print("

Python小白学习之路(十三)—【递归调用】

一.递归调用定义 在函数内部,可以调用其他函数. 如果在调用一个函数的过程中直接或间接调用自身本身,则称为递归调用 从某种意义上来说,递归调用可以实现无限循环 二.递归调用的特性 必须有一个明确的结束条件 每次进入更深一层递归时,问题规模相比上次递归都应有所减少 递归效率不高,递归层次过多会导致栈溢出 在计算机中,函数调用是通过栈(stack)这种数据结构实现的 每当进入一个函数调用,栈就会加一层栈帧 每当函数返回,栈就会减一层栈帧 由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出

Android学习之路——Android四大组件之activity(二)

上一篇讲了activity的创建和启动,这一篇,我们来讲讲activity的数据传递 activity之间的数据传递,这里主要介绍的是activity之间简单数据的传递,直接用bundle传递基本数据类型的数据.还有一种数据类型是parcelable和serialable 用bundle 传递数据有两种情况,这篇文章就分别从两个方面说明一下. 一.利用bundle传递基本数据类型 1.启动时传递数据,使用intent的put方法,将数据写入bundle中,然后startActivity(inte

winform学习日志(三十)----------从字符串总分离文件路径、命名、扩展名,Substring(),LastIndexOf()的使用;替换某一类字符串,Replace()的用法

一:从字符串总分离文件路径.命名.扩展名,上图 二:代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace FilePathString { public par

黑马程序员 【】java学习之路——TCP(三)客户端上传文件到服务器

------- <a href="http://www.itheima.com" target="blank">android培训</a>.<a href="http://www.itheima.com" target="blank">java培训</a>.期待与您交流! ---------- import java.io.*; import java.net.*; class