本文通过针对不同应用场景及其解决方案的方式,总结了Python中对文件与IO的一些相关知识,具体如下:

1.读写文本数据
应用场景:需要读取不同编码的文本数据,如ASCII,UTF-8,UTF-16等
解决方案:使用带有rt模式的open()函数

#读写文本文件
#1 single string 
with open('somefile.txt') as f:
    data=f.read

#2 迭代所有行
with open('somefile.txt','rt') as f:
    for line in f:
        print(line)
#3 重定向输出到文件
with open('somefile.txt','wt') as f:
    print(line1,file=f)
    print(line2,file=f)

#指定编码方式
with open('somefile.txt','rt',encoding='utf-8') as f:
    for line in f:
        print(line)

2.读写字节数据
应用场景:需要读取二进制文件,如图片、声音文件等
解决方案:使用带有rb、wb模式的open()函数

示例1
with open('somefile.bin','rb') as f:
    data=f.read(16)
    text=data.decode('utf-8')

with open('somefile.bin','wb') as f:
    text='helloword'
    f.write(text.encode('utf-8'))
示例2 数组和c结构体直接写入
import array
nums=array.array('i',[1,2,3,4])
with open('data.bin','wb') as f:
    f.write(nums)

3.读写压缩文件
应用场景:读写一个gzip或bz2格式的压缩文件
解决方案:使用gzip和bz2模块的open()函数

读:
import gzip
with gzip.open('somefile.gz','rt') as f:
    text=f.read()

import bz2
with bz2.open('somefile.bz2','rt') as f:
    text=f.read()
写:
import gzip
with gzip.open('somefile.gz','wt') as f:
    f.write(text)

import bz2
with bz2.open('somefile.bz2','wt') as f:
    f.write(text)

4.读取二进制数据到可变缓冲区
应用场景:需要直接读取二进制数据到一个缓冲区,而不需要做任何的中间复制操作
解决方案:使用文件对象的readinto()方法

示例
import os.path
def read_into_buffer(filename):
    buf=bytearray(os.path.getsize(filename))
    with open(filename,'rb') as f:
        f.readinto(buf)
    return buf

#test case
with open('sample.bin','wb') as f:
    f.write(b'helloworld')
buf=read_into_buffer('sample.bin')
buf
buf[0:5]=b'hahah'
buf
with open('newsample.bin','wb') as f:
    f.write(buf)

5.文件路径名 的操作
应用场景:需要使用路径名来获取问文件名、目录名、绝对路径等
解决方案:使用os.path模块中的函数来操作路径名

示例
import os 
path='/home/dw/ls-output.txt'
os.path.basename(path)
os.path.dirname(path)
os.path.join('tmp','data',os.path.basename(path))
path='~/ls-output.txt'
os.path.expanduser(path)
os.path.splitext(path)

6.增加或改变已经打开文件的编码
应用场景:想在不关闭一个已打开文件的前提下增加或者改变其Unicode编码
解决方案:使用io.TextIOWrapper()对象包装它

示例
import urllib.request
import io
u=urllib.reques.urlopen('http://www.python.ory')
f=io.TextIOWrapper(u,encoding='utf-8')
text=f.read()

import sys
sys.stdout.encoding
#detach移除已存在的文本编码层,使用新的编码方式代替
sys.stdout=io.TextIOWrapper(sys.stdout.detach(),encoding='latin-1')
sys.stdout.encoding

7.创建临时文件或文件夹
应用场景:需要在程序执行时创建一个临时文件或目录,使用完之后自动销毁
解决方案:使用tempfile.TemporaryFile

示例1 创建临时文件
from tempfile import TemporaryFile
#文本模式为w+t,二进制模式为w+b
with TemporaryFile('w+t') as f:
    f.write('helloworl\n')
    f.write('testing\n')
    #回溯并读取数据
    f.seek(0)
    data=f.read()
#临时文件自动被销毁
示例2创建临时目录
from tempfile import TemporaryDirectory
with TemporaryDirectory() as dirname:
    print('dirname is :',dirname)
    #此处可以使用上述创建的目录
#目录下的所有内容会自动销毁

8.序列化Python对象
应用场景:需要将一个Python对象序列化为一个字节流,以便将其保存到一个文件或存储到数据库或者通过网络传输它
解决方案:使用pickle模块

示例1
import pickle
data=...
f=open('somefile','wb')
pickle.dump(data,f)
#将对象转存为一个字符串
s=pickle.dumps(data)
#从字节流中恢复一个对象
f=open('somefile','rb')
data=pickle.load(f)
data=pickle.load(s)
示例2
class Countdown:
    def __init__(self,n):
        self.n=n
        self.thr=threading.Thread(target=self.run)
        self.thr.daemon=True
        self.thr.start()
    def run(self):
        while self.n>0:
            print('t-minus',self.n)
            self.n -=1
            time.sleep(5)
    def __getstate__(self):
        return self.n
    def __getstate__(self,n):
        self.__init__(n)
#test case
import countdown
c=countdown.Countdown(30)
t-minus 30

f=open('cstate.p','wb')
import pickle
pickle.dump(c,f)
f.close()
#退出python解析器并重启后再执行
f=open('cstate.p','rb')
pickle.load(f)