Python高效编程实战---4、文件IO高效处理技巧

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qd_ltf/article/details/79703632

一、如何读写文本文件

 # python2 下读写文本文件
f = open('txt.txt', 'w')
str = 'litaifa'  # 实际是字节串
str = u'你好,中国'  # unicode 串  以/0xff/0xe1形式存在
f.write(str.encode('gbk'))  # 需要将unicode串进行编码
f.close()
f = open('txt.txt', 'r')
s = f.read()
print s.decode('gbk')  # 将字符串s接照编码格式进行解码,程序默认按照utf8进行解码

# python3 下读写文本文件
str = b'litaifa'  # 如要想是字节串,需要在前面加b
print(type(str))  #<class 'bytes'>
str = '你好,中国'  # python3下默认都是unicode串
print(type(str))   # <class 'str'>

f = open('txt.txt', 'wt',encoding='gbk')  # 'wt'指按文本方式写入,encoding指定编码方式
f.write(str)  # 不需要将unicode串进行编码
f.close()
f = open('txt.txt', 'rt',encoding='gbk')  # encoding指定解码方式
s = f.read()  # 无需解码
print(s)

二、如何处理二进制文件

import struct, array

f = open('lbb.wav', 'rb')
info = f.read(44)

print struct.unpack('h', info[22:24])   # 将二进制数据取第22、23两个位上的字节进行解析
print struct.unpack('i', info[24:28])
print struct.unpack('h', info[34:36])

f.seek(0, 2)
# 文件指针指向文件末尾。第一个参数代表需要移动偏移的字节数,
# 第二个参数可选,默认值为 0。给offset参数一个定义,表示要从哪个位置开始偏移;
# 0代表从文件开头开始算起,
# 1代表从当前位置开始算起,
# 2代表从文件末尾算起。
data_len = (f.tell() - 44) / 2   # tell()返回当前指针位置,data_len为缓存的长度
buf = array.array('h', (0 for _ in xrange(data_len)))  # 创建一个数组,第二个参数为可迭代对象或列表
f.seek(44)  # 将指针指向数据部分的起点
f.readinto(buf)   # 将指针后面的数据读到缓存中
f.close()
for i in xrange(data_len):
    buf[i]/=16  # 将每个数据值除16,声音变小?

f2=open('lbb_bax.wav','wb')  
f2.write(info)  # 二进制串直接写入
buf.tofile(f2)  # 缓存数据写入到文件
f2.close()

三、如何设置文件的缓冲

f=open(‘deom1.txt’,’w’,buffering=) python在保存文件时,是按照块进行保存,默认一个块是4096个字节,当缓冲达到4096个字节时,保存到磁盘上。也可以自定义块的大小
1. 全缓冲:buffering= 大于1的整数n 表示缓冲达到n个字节,即存入磁盘
2. 行缓冲:buffering= 等于1,缓冲遇到回车,即存入磁盘
3. 无缓冲:buffering= 等于0

四、如何将文件映射到内存

# 不仅可以映射二进制,文本文件也可以
import mmap

f = open('demo.bin', 'r+b', ) # 二进制读写的方式打开
# fileno()文件描述号
# 第二个参数,0表示全部映射,
# access= 指定文件的权限 offset= 指定文件偏移量,必须是mmap.PAGESIZE的整数倍

m = mmap.mmap(f.fileno(), mmap.PAGESIZE*4, access=mmap.ACCESS_WRITE)
m = mmap.mmap(f.fileno(), mmap.PAGESIZE * 4, access=mmap.ACCESS_WRITE, offset= mmap.PAGESIZE * 2)
m[0] = '\x88'  # 修改映射,同时也修改了文件
m[20:40] = '\xaa' * 20
print len(m)  # 页的倍数
print mmap.PAGESIZE  # 为4096

五、如何访问文件的状态

方法1:通过os原始接口,stat() , lstat(),fstat()

   stat()      文件所有属性
   lstat()     不查看链接文件类型 
   fstat()     传入参数为文件描叙符,例:f=open('t.txt','r') 
   fstat(f.fileno())
import os
import stat
s = os.stat('python.PNG')    
print(stat.S_ISDIR(s.st_mode)) # 判断文件是否为目录
print(stat.S_ISREG(s.st_mode))  # 判断文件是否是普通文件

# 判断文件权限
print(s.st_mode & stat.S_IRUSR)    # 可读,user,大于0为真
print(s.st_mode & stat.S_IXGRP)   # 可执行,user

# 获取文件 访问、修改、节点状态 时间
import time
print(time.localtime(s.st_atime))  # s.st_atime得到的是秒数,需要转换为时间
print(time.localtime(s.st_ctime))
print(time.localtime(s.st_mtime))

方法2:os.path下的方法,更简洁重点内容

import os
print(os.path.isdir('python.PNG'))  # 判断文件是否为目录
print(os.path.isfile('python.PNG'))  # 判断文件是否是普通文件

# 获取文件 访问、修改、节点状态 时间
import time
print(time.localtime(os.path.getatime('python.PNG')) )
print(time.localtime(os.path.getmtime('python.PNG')) )
print(time.localtime(os.path.getctime('python.PNG')) )

六、如何使用临时文件

from tempfile import TemporaryFile,NamedTemporaryFile
from tempfile import 

f = TemporaryFile()   # 关闭文件时候删除 
f_2 = NamedTemporaryFile(delete=False)   # delete默认删除,为True则关闭临时文件时候不删除,
f.write(b'abcd'*100)
f_2.write(b'abcd'*100)

# 并不能自主命名。系统分配名字,只能写入bytes类型
print(f_2.name, f.name)

七、关于二进制文件

  1. 使用二进制文件的好处

    1. 二进制文件比较节约空间,这两者储存字符型数据时并没有差别。但是在储存数字,特别是实型数字时,二进制更节省空间,比如储存 Real*4 的数据:3.1415927,文本文件需要 9 个字节,分别储存:3 . 1 4 1 5 9 2 7 这 9 个 ASCII 值,而二进制文件只需要 4 个字节(DB 0F 49 40)
    2. 内存中参加计算的数据都是用二进制无格式储存起来的,因此,使用二进制储存到文件就更快捷。如果储存为文本文件,则需要一个转换的过程。在数据量很大的时候,两者就会有明显的速度差别了。
    3. 就是一些比较精确的数据,使用二进制储存不会造成有效位的丢失。
  2. python处理二进制文件
      python没有二进制类型,但可以存储二进制类型的数据,就是用string字符串类型来存储二进制数据,这也没关系,因为string是以1个字节为单位的。
    将字符串转换为二进

    import struct
    a=12
    bytes=struct.pack('i',a)   # 将a变为二进制  结果为: '\x0c'ytes就是一个string字符串,字符串按字节同a的二进制存储内容相同。

    将二进制数据转换成python的数据类型

    a,=struct.unpack('i',bytes) # unpack返回的是tuple
    (a,)=struct.unpack('i',bytes)   # 另外一种写法

    果是由多个数据构成的,可以这样:

    a='hello'
    b='world!'
    c=2
    d=45.123
    bytes=struct.pack('5s6sif',a,b,c,d)

    此时的bytes就是二进制形式的数据了,可以直接写入文件比如 binfile.write(bytes)
    然后,当我们需要时可以再读出来,bytes=binfile.read()
    再通过struct.unpack()解码成python变量
    a,b,c,d=struct.unpack(‘5s6sif’,bytes)
    ‘5s6sif’这个叫做fmt,就是格式化字符串,由数字加字符构成,5s表示占5个字符的字符串,2i,表示2个整数等等

  3. 二进制文件处理时会碰到的问题
     我们使用处理二进制文件时,需要用如下方法
    binfile=open(filepath,’rb’) 读二进制文件 或 binfile=open(filepath,’wb’) 写二进制文件
    那么和binfile=open(filepath,’r’)的结果到底有何不同呢?
    不同之处有两个地方:

    a. 使用’r’的时候如果碰到’0x1A’,就会视为文件结束,这就是EOF。使用’rb’则不存在这个问题。即,如果你用二进制写入再用文本读出的话,如果其中存在’0X1A’,就只会读出文件的一部分。使用’rb’的时候会一直读到文件末尾。
    b. 对于字符串x=’abc/ndef’,我们可用len(x)得到它的长度为7,/n我们称之为换行符,实际上是 ‘0X0A’。当我们用’w’, 即文本方式写的时候,在windows平台上会自动将’0X0A’变成两个字符’0X0D’,’0X0A’,即文件长度实际上变成8.。当用’r’文本方式读取时,又自动的转换成原来的换行符。如果换成’wb’二进制方式来写的话,则会保持一个字符不变,读取时也是原样读取。所以如果用文本方式写入,用二进制方式读取的话,就要考虑这多出的一个字节了。’0X0D’又称回车符。linux下不会变。因为linux只使用’0X0A’来表示换行。

猜你喜欢

转载自blog.csdn.net/qd_ltf/article/details/79703632