python文件操作(二)

一、二进制处理文件

       通过前面的说明,我们知道‘b’模式是通过字节的形式来读写文件,但是要理解一点的是,这种模式只是在内部处理的时候是字节,但是我们打开文件看到的还是字符串的形式,而不是一堆字节。还有一点需要了解的是,在linux系统里面,‘b’模式是没有作用的,因为linux理念的是一切皆文件,他本来所有的文件都是通过字节操作的,所以如果要跨平台处理文件,需要用到‘b’模式。

1.‘rb’模式

       下面就来演示‘b’模式读取一个py文件,py文件的内容如下: 

hello
11111
22222
33333

       根据前面的内容,我们一般这么写:

f=open('test11.py','rb',encoding='utf-8') #b的方式不能指定编码
data=f.read()
print(data)
f.close()

        但是运行后会发现报错,ValueError: binary mode doesn't take an encoding argument,b的方式不能指定编码,为什么不能指定?因为你文件存在硬盘的方式就是一堆二进制,之所以你能看到字符串,是因为你是用应用程序打开的文件,应用程序有不同的编码方式,所以如果你是‘r’模式去读,要区分编码,如果是‘rb’模式去读,读的是原生的二进制,就不用应用程序编码了,所以会报错。

      所以正确的写法是这样的:

 

f=open('test11.py','rb') #b的方式不能指定编码
data=f.read()
print(data)
f.close()

 

      拿到的结果是:

b'hello\r\n11111\r\n22222\r\n33333'

      前面这个b,就说面这一个字节内容,如果在源文件加一列中文,结果会是:

b'hello\r\n11111\r\n22222\r\n33333\r\n\xe4\xbd\xa0\xe5\xa5\xbd'

      如果你想看到你原本写的字符串,就要对结果进行解码(对应你写入字符串时的编码,我这里写入时为‘utf-8’编码),也就是decode:

f=open('test11.py','rb') #b的方式不能指定编码
data=f.read()
#'字符串'---------encode---------》bytes
#bytes---------decode---------》'字符串'
# print(data)
print(data.decode('utf-8'))
f.close()

      这时看到的结果就是:

hello
11111
22222
33333
你好

      这里有一个小的补充:windows里面的回车\r\n,linux和unix的回车则直接是\n,所以跨系统传文件打开后看到的会有一些偏差,原因可能就是这个。

2.‘wb’模式

      读文件我们会了,写文件也是一样的,我们写入也要写入bytes形式的,字符串转换成字节可以通过bytes()函数实现。

f=open('test22.py','wb') #b的方式不能指定编码
f.write(bytes('1111\n',encoding='utf-8'))
f.close()

       运行完之后我们拿到一个新文件,里面的内容就是1111,这里面写中文也是可以的。字符串转字节是一种编码过程,那我们是不是可以用encode方法呢?

f=open('test22.py','wb') #b的方式不能指定编码
# f.write(bytes('你好\n',encoding='utf-8'))
f.write('你好'.encode('utf-8'))
f.close()

     运行完之后,结果同样OK。‘ab’模式用法就不多说了,和前面的a类似。现在有一个疑问,为什么我们要用b模式来处理文件?那我用r/w/a也可以完成上面的操作。原因有两点:

1.文件不仅仅只有文本这一种形式,还有图片视频等,这些非文本形式你用r/w/a处理不了;

2.就是之前说过的,你需要跨平台处理文件的时候,不管你什么平台,你最后处理的都是一堆二进制;

二、文件操作的其他方法

     操作文件的方法除了之前说read、readlines、readline、write等,还有其他方法可以了解一下:

1.f.encoding (如果文件打开模式为b,则没有该属性)

f=open('a.txt','r+',encoding='gb2312')
print(f.encoding)
f.close()

>>>gb2312

       这里拿到的文件打开的编码,切记,和源文件以什么方式存放到硬盘的方式无关。无法解决你因为不知道源文件编码时,打开文件乱码的问题。不过这种情况很少见,大部分情况你都是知道源文件编码的,如果真的遇到这种情况,就可以用一种encoding='latin-1'的编码去打开,这种编码兼容了大部分的编码方式。

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

       当你通过open打开一个文件的时候,你写的东西其实都是内存里面,并没有保存在硬盘中,你不保存,这些数据就一直在内存中,假如关闭或断电了就没了。可是你会发现这种情况在pycharm里面,你没有保存,文件内容断电之后也还存在,这是因为这些应用程序每隔几秒就自动帮你保存一次,这种保存的方法就是flush(),你可以在cmd里面实验这种情况。

3.f.tell() (返回文件光标所在的位置)

        现在有一个文件,就写了一行hello,看看tell返回什么   

f=open('b.txt','r',encoding='utf-8')
print(f.tell())
f.readline()
print(f.tell())

>>>0
>>>5

        返回的就是当前光标的位置,注意当有多行时,会加上回车的两个字节。

4.python做的好事!

       上面我们说过,Windows的回车是\r\n,下面看一下:

f=open('b.txt','r',encoding='utf-8')
print(f.readlines())
f.close()

>>>['hello\n', '11111']

       怎么我打印出来只有\n呢?这就是python帮你处理过的结果,想要拿到真正的结果,还要加上一个newline=''

f=open('b.txt','r+',encoding='utf-8',newline='') #读取文件中真正的换行符号
print(f.readlines())
f.close()

>>>['hello\r\n', '11111']

        这样拿到的才是真实的结果,不过这没什么用,了解一下就行。

5.f.seek()

       在讲这个之前,要先了解一下光标移动的两个点:

       一: read(3):

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

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

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

f=open('b.txt','r+',encoding='utf-8')
f.seek(1)
print(f.tell())
f.seek(3)
print(f.tell())

>>>1
>>>3

      这就很容易理解了,但是如果你是中文开头的,一个中文是3个字节,你seek(1)的话就要报错了。还有一点就是,这里的seek都是以0为基准进行移动的。这种是默认情况,seek有三种移动方式0,1,2,其中1和2必须在b模式下进行,但无论哪种模式,都是以bytes为单位移动的。建议试一下read和seek的区别。

f=open('b.txt','rb')
print(f.tell())
f.seek(10,1)
print(f.tell())
f.seek(3,1)
print(f.tell())

>>>0
>>>10
>>>13

       从上可知,seek模式改为1,就变为相对位置了。再改为2试试:

f=open('b.txt','rb')
print(f.tell())
f.seek(-5,2)
print(f.read())
print(f.tell())
f.seek(3,1)
print(f.tell())

>>>0
>>>b'11111'
>>>12
>>>15

       模式2就是倒着seek,倒着移动的话,里面的参数也要写成负数,注意了。那么这个seek有什么用呢,就要在实际场景中去思考了。

6. f.truncate([size]) 把文件裁成规定的大小

    如果size比文件大小还大, 这个会根据系统的不同可能不改变文件,可能补充0进去,或者补充一些随机的内容。truncate(10)就是从开头截取到第10个字节。所以文件的打开方式必须可写,但是不能用w或w+等方式打开,因为那样直接清空文件了,所以truncate要在r+或a或a+等模式下进行。

    其他方法很少用到,了解一下就行了。

 

 

 

 

 

 

 

 

 

 

         

posted @ 2019-05-06 18:57  彭方炎QAQ  阅读(305)  评论(0编辑  收藏  举报