Python 文件操作

1、文本与二进制文件

文本文件

打开记事本就可以阅读的文件
优点:输出内容友好,不需要手动转换
缺点: 一个字符占一个字节,文件占用的存储空间较多,读写需要转换(内存—>显示),访问时效率不高

二进制文件

这类文件将数据按照它的进制编码的形式存储。
如BMP。由 于这类文件内容是二进制编码,使用记事本打开是显然是乱码,BMP可用图片查看器解码
优点:二进制文件中的数据与数据在内存中的表现形式一致,存储数据占用空间较少,读写不需要进行转换,效率高
缺点:二进制文件无法直接以字符形式输出,必须 要经过一个转换过程

2、文本编码

对于计算机来说,所有信息都是由0和1组成的二进制。 人类无法仅用二进制就来完成计算机的各种操作 字符编码解决人与计算机之间的沟通问题。

编码解释
ascii码对英文字符进行编码, ord(“字符”)查看ascii码
unicode码万国码 基本上所有的文字都给一个编码
utf-8、 utf-16 、utf-32 、 gbk都是unicode的具体实现方式

python2中默认编码ascii码
python3中默认编码是utf-8

编码占用字节数
utf-8一个英文占用一个字节,一个中文字符占用3个字节
gbk一个字符占用俩个字节,如果中文比较多,建议使用gbk

如果中文比较多,建议使用gbk,减少空间消耗
以什么方式加码,就要以什么方式解码
如果文件加码和解码的方式不一致,就会出现乱码的情况
在这里插入图片描述

>>> str1 = "中文"
>>> str1.encode("utf-8")       #加码
b'\xe4\xb8\xad\xe6\x96\x87'    6个字节
>>> b'\xe4\xb8\xad\xe6\x96\x87'.decode("utf-8")  #解码
'中文'
>>> str1.encode("utf-16")      
b'\xff\xfe-N\x87e'             3个字节
>>> str1.encode("utf-32")
b'\xff\xfe\x00\x00-N\x00\x00\x87e\x00\x00'  9个字节
>>> str1.encode("gbk")         
b'\xd6\xd0\xce\xc4'            4个字节

3、文件的缓冲机制

1)读操作

不会直接对磁盘进行读取,而是先打开数据流,将磁盘里的文件拷贝到缓冲区,程序从缓冲区读取所需数据
在这里插入图片描述

2) 写操作

不会马上写入到磁盘,而是先写到缓冲区,只有缓冲区已满或 有“关闭文件” 操作的时候,才会将数据写入磁盘
在这里插入图片描述

3)文件缓冲区

计算机系统为要处理的文件在内存中单独开辟出来的一个存储区间,在读写该文件时,做为数据交换的 临时“存储中转站

4)缓冲机制的好处

能够有效地减少对外部设备的频繁访问,减少内存与外设间的数据交换,填补内、外设备的速度差异, 提高数据读写的效率

4、文件的基本操作

1)文件的编码方式

[root@localhost open_py]# locale   
#Locale是根据计算机用户所使用的语言,所在国家或者地区,以及当地的文化传统所定义的一个软件运行时的语言环境
LANG=zh_CN.UTF-8     
LC_CTYPE="zh_CN.UTF-8" #语言符号及其分类
LC_NUMERIC="zh_CN.UTF-8" #数字
LC_TIME="zh_CN.UTF-8"  #时间显示格式
LC_COLLATE="zh_CN.UTF-8" #比较和排序习惯
LC_MONETARY="zh_CN.UTF-8" #货币单位
LC_MESSAGES="zh_CN.UTF-8" #信息主要是提示信息,错误信息,状态信息,标题,标签,按钮和菜单等
LC_PAPER="zh_CN.UTF-8"  #默认纸张尺寸大小
LC_NAME="zh_CN.UTF-8"  #姓名书写方式
LC_ADDRESS="zh_CN.UTF-8"  #地址书写方式
LC_TELEPHONE="zh_CN.UTF-8" #电话号码书写方式
LC_MEASUREMENT="zh_CN.UTF-8" #度量衡表达方式
LC_IDENTIFICATION="zh_CN.UTF-8"  #对locale自身包含信息的概述
LC_ALL=
[root@localhost open_py]# iconv -f utf-8 -t gbk gbk.txt >>gbk2.txt  对文件编码进行转换,utf8转gbk
[root@localhost open_py]# cat gbk2.txt
▒▒▒▒GBKK
[root@localhost open_py]# file gbk2.txt   Linux 查看文件类型,包含编码
gbk2.txt: ISO-8859 text

>>> fp = open("utf8.txt")  python3 默认是utf-8 解码,所以能解码utf8的文件
>>> fp.read()
'这是utf-8\n'
>>> fp = open("gbk2.txt")   gbk2.txt是gbk编码加码的,utf8是解不了的,报错
>>> fp.read()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python3.6/codecs.py", line 321, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd5 in position 0: invalid continuation byte
>>> fp = open("gbk2.txt",encoding="gbk")   指定解码格式
>>> fp.read()
'这是GBKK\n'

python文件编码检测
安装模块pip3 install chardet
后重新进入python3环境导入这个模块

>>> import chardet
>>> fp = open("utf8.txt","rb")   #以二进制读的方式打开
>>> chardet.detect(fp.read())    
{'encoding': 'utf-8', 'confidence': 0.7525, 'language': ''}
>>> fp = open("gbk2.txt","rb")
>>> chardet.detect(fp.read())
{'encoding': 'ISO-8859-5', 'confidence': 0.38398486178080915, 'language': 'Russian'}

2)文件的打开方式

  • 文件打开方式:
    读 读写 追加写 覆盖写
  • 文件类型的打开方式:
    二进制类型文件 、文本类型
open()
open(file, mode='r', buffering=-1, encoding=None, errors=None, 
     newline=None, closefd=True, opener=None)
Open file and return a stream.  Raise IOError upon failure.

file:要打开的文件名( str )
mode:打开文件的方式( str ) => text, bytes
buffering:缓存方式 ( int)
encoding:文件编码方式 (encoding=None表示系统是什么编码,这里就使用什么编码)

返回的对象是文件打开对象
这个对象是上下文管理器对象,可以使用with语句去管理

  • 一般的读写模式有:
    w 以写的方式打开(会覆盖原有的文件)
    r 以只读的方式打开
    a 以追加的模式打开(在原文件的末尾追加要写入的数据,不覆盖原文件)
    b 以二进制文件的方式打开
    r+ w+ a+ 都是以读写的方式打开
    rb 以二进制读的方式打开
    wb 以二进制写的方式打开
    ab 以二进制追加的模式打开
    rb+ wb+ ab+ 以二进制读写的方式打开·

在这里插入图片描述

>>> fp.close()  关闭的时候缓冲区的文件会写到磁盘
>>> fp = open("test.txt","w")   覆盖写
>>> fp.write("this is test2")    
13
>>> fp.flush()  强制将缓冲区的内容刷新到磁盘
>>>> fp = open("test.txt","a")   追加写
>>> fp.write("this is test3 追加写")
17
>>> fp.flush()
with open()

自动实现fp文件连接的关闭
实现这部分资源的回收

with open("test.txt","a") as fp:
    fp.write("append str!!!!")

fp.write("ddddd")   #写不了
print("ending....")

3)文件的缓存刷新

buffering 缓存设置
文件的读写:读到内存里面,再从内存的缓冲区域进行读写

可以通过buf去设置写缓冲的方式
0: 实时写入,不缓存,只适用于二进制模式
1:行缓存,遇到换行符就写入磁盘, 只适用于文本模式
2~n:表示缓冲区的大小 2*4069个字节

>>> fp = open("test.txt","wb",buffering=0)  实时写入
>>> fp.write(b"this is test")  
>12 
>>>> fp.write(b"\nthis is test") 
>>> fp = open("test.txt","w",buffering=1)  行缓存
>>>> fp.write("this is test\n")                                                              
13 
>>> fp = open("test.txt","w",buffering=2) 
>>> fp.write("a"*4096)  一个英文字母是一个字节
>>>4096
>>>> fp.write("a"*4096) 
>>>4096
>>>> fp.write("a"*4096) 此时缓存区满,刷到缓存
>>>4096

4) 文件的读取

fp.read() 从光标位置到文末 ,也可以在括号里面指定读取多少字符
fp.readline() 从光标位置到行末
fp.readlines() 返回当前光标行的内容,每行作为一个元素,返回一个列表
fp.seek()重置光标
for i in f: 文件可以按行读取

>>> fp = open("test.txt")
>>> fp.readline()   每次读取一行
'aa\n'
>>> fp.readlines()   每行作为一个元素,返回一个列表
['bbb\n', 'ccc\n', 'ddd\n', 'eee\n', '\n']
>>> fp.seek(0)
0
>>> fp.read(7)  指定读取字符数
'aa\nbbb\n'
>>> fp.tell()
7
>>> fp.seek(2)  
2

在这里插入图片描述

fp = open("example2.txt")
lst = fp.readlines()
fp.seek(0)
l = len(lst)
for i in range(l):
    line =fp.readline()
    if line[0] != '#':
        print(line)
练习1

 准备一个example.txt文件, 里面随便写入些内容(如一首歌词)
 读前5行。
 读全文
 读取最后12字节 => str格式
 读取最后4个汉字 => str格式

with open("test.txt", "rb") as fp:
    for i in range(5):
        print(fp.readline().decode("utf-8"))
    fp.seek(0)

    # print(fp.read().decode("utf-8"))
    
    fp.seek(-12, 2)
    print(fp.read().decode("utf-8"))
练习2

读取一个文件,显示除了以井号(#)开头的行以外的所有行

with open("test.txt", "rb") as f:
    for i in f:  # 文件可以按行读取
        s = i.decode("utf-8")
        if s[0] != '#':
            print(s)  

对于大文件的读写,不要使用read或readlines,它会一次性地将文件内容读入内存,造成oom
可以用for循环一行一行地读,读完就可以在内存里面删掉。
但是效率低。
fp.read(6000) 读取6000个字符
fp.readlines(6) 读 取第6个字符所在行以及之前的行

5)文件的写入

  • 写文件为什么不实时写入磁盘?
    磁盘是慢设备,频率读写会增加磁盘压力,产生瓶颈
  • 默认什么情况下将缓存写入磁盘?
    1、fp.close() 文件连接关闭的时候
    2、fp.flush() 强制刷新到磁盘
    3、缓冲区满的时候将文件内容刷新到磁盘
    4、程序退出的时候
    5、buffer设置(默认:io.DEFAULT_BUFFER_SIZE )
    • 0 => 实时写入 (binary mode)
    • 1 => 行缓存 ( text mode) => \n
    • 其他数字n => 缓冲区大小n : 2*4096

6)文件对象的其他方法

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

这个手刹不太灵儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值