Cookbook:5.文件和IO

本文档详细介绍了Python中各种文件和IO操作,包括读写文本数据、重定向输出、处理压缩文件、内存映射、序列化对象等,涵盖了open()函数、io模块、gzip/bz2模块、tempfile模块及pickle模块的使用方法。
摘要由CSDN通过智能技术生成

1.读写文本数据

对文本数据进行读写操作,可能涉及到多种编码

解决:用 open() 配合 rt 模式

with open('somefile.txt','rt') as f:
    data=f.read()

读写操作 open( ) wt 模式

wt 模式:如果文件已存在,会清除原先内容

书 P144

2.将输出重定向到文件

将print函数加上file参数即可:

with open('somefile.text','rt') as f:
    print('ssss',file=f)
    #确保文件是文本模式打开的,二进制的话会失败

3.以不同分隔符或行结尾符完成打印

print函数使用 sep 和 end 关键字参数

print('asas',50,23,sep=',')

print('das',2312,222,end='!!\n')
str.join()
print(','.join('acme',50,912))
#即将,插入进去

4.读写二进制数据

二进制数据如图像、声音

open() rb wb参数
with open('somefile.bin','rb') as f:
    data = f.read()

读写二进制文件,要确保编码和解码操作

with open('some.txt','rb') as f:
    data = f.read(16)
    text = data.decode('utf-8')
    
with open('some.txt','rb') as f:
    text = 'hello world'
    f.write(text.encode('utf-8'))

想数组和c结构体这样的对象可以直接用来进行写操作:

import array
nums = array.array('i',[1,2,3,4])
with open('data.bin','wb') as f:
    f.write(nums)

5.对已不存在的文件执行写入

open()函数 的 x模式替代 w模式

with open('somefile','wt') as f:
        f.write('Hello\n')
        
        
with open('somefile','xt') as f:
        f.write('Hello\n')

或者先检查文件是否存在:

import os 
if not os.path.exists('somefile'):
    with open('somefile','wt') as f:
        f.write('Hello\n')
       else:
        print('File already exists!')

6.在字符串上执行I/O操作

我们想将一段文本或二进制字符串写入类似文件的对象上

io.StringIO() io.BytesIO()
import io
s = io.StringIO()
s.write('Hello world\n')
12
s.getvalue()
'Hello world\n'
print('This is a text\n',file=s)
s.getvalue()
'Hello world\nThis is a text\n\n'

如果是二进制数据,要用ByteIo

f = io.BytesIO()
f.write(b'binary data')
11
f.getvalue()
b'binary data'

7.读写压缩的数据文件

如 gzip \ bz2 格式

gizp模块 bz2模块
import gzip
with gzip.open('somefile.gz','rt') as f:
    text = f.read()

cookbook P 151

8.对固定大小的记录进行迭代

iter() functools.partial()
from functools import partial
RECORD_SIZE = 32
with open('somefile.data','rb') as f:
    records = iter(partial(f.read,RECORD_SZIE),b'')
    for r in records:
        ...

附录A:Python的functools模块

partial

用于创建一个偏函数,将默认参数包装一个可调用对象,返回结果也是可调用对象。
偏函数可以固定住原函数的部分参数,从而在调用时更简单。

from functools import partial

int2 = partial(int, base=8)
print(int2('123'))
# 83
12345
update_wrapper

使用 partial 包装的函数是没有__name____doc__属性的。
update_wrapper 作用:将被包装函数的__name__等属性,拷贝到新的函数中去。

from functools import update_wrapper
def wrap2(func):
	def inner(*args):
		return func(*args)
	return update_wrapper(inner, func)

@wrap2
def demo():
	print('hello world')

print(demo.__name__)
# demo
123456789101112
wraps

warps 函数是为了在装饰器拷贝被装饰函数的__name__
就是在update_wrapper上进行一个包装

from functools import wraps
def wrap1(func):
	@wraps(func)	# 去掉就会返回inner
	def inner(*args):
		print(func.__name__)
		return func(*args)
	return inner

@wrap1
def demo():
	print('hello world')

print(demo.__name__)
# demo
1234567891011121314
reduce

在 Python2 中等同于内建函数 reduce
函数的作用是将一个序列归纳为一个输出
reduce(function, sequence, startValue)

from functools import reduce

l = range(1,50)
print(reduce(lambda x,y:x+y, l))
# 1225
12345
cmp_to_key

在 list.sort 和 内建函数 sorted 中都有一个 key 参数

x = ['hello','worl','ni']
x.sort(key=len)
print(x)
# ['ni', 'worl', 'hello']
1234
  • Python3 之前还提供了cmp参数来比较两个元素
  • cmp_to_key 函数就是用来将老式的比较函数转化为 key 函数
lru_cache

允许我们将一个函数的返回值快速地缓存或取消缓存。
该装饰器用于缓存函数的调用结果,对于需要多次调用的函数,而且每次调用参数都相同,则可以用该装饰器缓存调用结果,从而加快程序运行。
该装饰器会将不同的调用结果缓存在内存中,因此需要注意内存占用问题。

from functools import lru_cache
@lru_cache(maxsize=30)  # maxsize参数告诉lru_cache缓存最近多少个返回值
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)
print([fib(n) for n in range(10)])
fib.cache_clear()   # 清空缓存
12345678

9.将二进制数据读取到可变缓冲区

readinto()
import os.path
def read_into_buffer(filename):
    buf = bytearray(os.path.getsize(filename))
    with open(filename,'rb') as f:
        f.readinto(buf)
    retirn buf
    
    #下面是用法
    with open('sample.bin','wb') as f:
...     f.write(b'Hello world')
...     
buf = read_into_buffer('sample.bin')
buf
bytearray(b'Hello world')

10.对二进制文件做内存映射

将一个二进制文件加载到可变的字节数组中

mmap模块
Python 3.7.9 (default, Aug 31 2020, 17:10:11) [MSC v.1916 64 bit (AMD64)] on win32
import os
... import mmap
... 
... def memory_map(filename ,access=mmap.ACCESS_WRITE):
...     size = os.path.getsize(filename)
...     fd = os.open(filename, os.O_RDWR)
...     return mmap.mmap(fd, size, access=access)
... 
... 
size=100000
with open('sample.bin','wb') as f:
...     f.seek(size-1)
...     f.write(b'\x00')
...     

这个不懂 书P155

11.处理路径名

os.path的函数

import os
path ='D:\pycharmProjects\data_sample.csv'
os.path.basename(path)
'data_sample.csv'

os.path.dirname(path)
'D:\\pycharmProjects'

12.检测文件是否存在

os.path.exists(’’)

返回ture 和false

>>>os.path.getsize(path)
87
>>>os.path.getmtime(path)
1608446350.6606245
>>>os.path.islink(path)
False
>>>os.path.isdir(path)
False
>>>os.path.realpath(path)
'D:\\pycharmProjects\\data_sample.csv'

13.获取目录内容的列表

os.listdir()

将得到原始目录文件列表

>>>names = os.listdir('D:\pycharmProjects')
>>>names
['.idea', '1.py', 'bi_load.py', 'data_sample.csv', 'error_check.py', 'heap.py', 'homework_03', 'homework_04', 'iteration.py', 'iter_text.py', 'main.py', 'main2.py', 'maxprofit.py', 'maxSubList.py', 'sample.bin', 'simple_bpNN', 'somefile.txt', 'venv', '__pycache__']

endswith 和 startswith 也可使用

>>>dirnames =[name for name in os.listdir('D:\pycharmProjects') if name.endswith('.py')]
>>>dirnames
['1.py', 'bi_load.py', 'error_check.py', 'heap.py', 'iteration.py', 'iter_text.py', 'main.py', 'main2.py', 'maxprofit.py', 'maxSubList.py']

至于文件名的匹配,可以用到glob 和 fnmatch模块

>>>import glob
>>>pyfiles = glob.glob('D:\pycharmProjects\*.py')
>>>pyfiles
['D:\\pycharmProjects\\1.py', 'D:\\pycharmProjects\\bi_load.py', 'D:\\pycharmProjects\\error_check.py', 'D:\\pycharmProjects\\heap.py', 'D:\\pycharmProjects\\iteration.py', 'D:\\pycharmProjects\\iter_text.py', 'D:\\pycharmProjects\\main.py', 'D:\\pycharmProjects\\main2.py', 'D:\\pycharmProjects\\maxprofit.py', 'D:\\pycharmProjects\\maxSubList.py']

>>>from fnmatch import fnmatch
>>>pyfiles = [name for name in os.listdir('') if fnmatch(name,'*.py')]

以上只是得到目录列表的条目名称,如果想要得到如 文件大小,修改日期等,可用os.path 模块或 os.stat()函数

>>>pyfiles = glob.glob('*.py')
>>>name_sz_date =[(name, os.path.getsize(name), os.path.getmtime(name)) for name in pyfiles]
>>>for name, size, mtime in name_sz_date:
...     print(name, size, mtime)
...     
1.py 358 1606379370.7863636
bi_load.py 205 1608445939.1266453
error_check.py 339 1607431357.4926434
heap.py 0 1607251664.313212
iteration.py 379 1606723461.9875746
iter_text.py 428 1606550544.0579054
main.py 325 1606550350.4782178
main2.py 259 1606723479.0354326
maxprofit.py 501 1607045771.2621334
maxSubList.py 447 1608300845.34697

14.绕过文件命编码

默认情况下,所有文件名都会根据 sys.getfilesystemencoding() 返回的文本编码形式进行编码和解码

>>>import sys
>>>sys.getfilesystemencoding()
'utf-8'

如果基于某些原因想忽略这种编码,可以使用原始字节串来指定文件名

15.打印无法解决的文件名

出现异常UnicodeEncodeError,并伴随 “surrogates not allowed”

可以用以下方式避免出现错误:

def bad_filename(filename):
    return repr(filename)[1:-1]
try:
    print(filename)
except UnicodeEncodeError:
    print(bad_filename(filename))

16.为已经打开的文件修改或添加编码方式

io.TextIOWrapper()

使用io.TextIOWrapper 将其包装

import urllib.request
import io

u = urllib.request.urlopen('http:\\www.python.org')
f = io.TextIOWrapper(u,encoding='utf-8')
text = f.read()

如果想修改一个已经以文本模式打开的编码方式,可以在用新的编码替换之前的编码前,用detach()方法将已有的文件编码层移除

>>>import sys
>>>sys.stdout.encoding
'UTF-8'
>>>sys.stdout = io.TextIOWrapper(sys.stdout.detach(),encoding='lating-1')
>>>sys.stdout.encoding
'lating-1'

17.将字节数据写入文本文件

只需要简单地将字节数据写入文件底层的buffer中,如下:

>>>import sys
>>>sys.stdout.write(b'Hello\n')
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: write() argument must be str, not bytes
>>>sys.stdout.buffer.write(b'Hello\n')
Hello
6

也可以通过buffer属性读取文件二进制数据

I/O系统 是以不同的层次来构建的,文本文件是通过在缓冲的二进制模式文件之上添加一个Unicode编码、解码层来构建的。buffer属性简单地指向底层的文件。如果访问该属性,就可以绕过文本编码/解码层了。

18.将已有的文件描述符包装为文件对象

文件描述符只是一个由操作系统分配的整数句柄,用来指代某种系统I/O通道。如果刚好有这样一个文件描述符,就可以通过open()函数用python文件对象对其进行包装。

import os
fd = os.open('somefile.txt',os.O_WRONGLY | os.O_CREAT)

f = open(fd,'wt')
f.write('hello\n')
f.close()

高层的文件对象关闭或则销毁时,底层的文件描述符也会关闭,如果不想要,给open()提供可选参数即可。

f = open(fd, 'wt', closed=False)

P168

19.创建临时文件和目录

tempfile模块
from tempfile import TemporaryFile

with TemporaryFile('w+t') as f:
    f.write('Hello World\n')
    f.write('Testing\n')

    f.seek(0)
    data = f.read()

    # 用完销毁
    # 或者 f.TemporaryFile('w+t')

P170

20.同串口进行通信

通过串口读取和写入数据。

serial

P172

21.序列化python对象

我们需要将python对象序列化为字节流,这样就可以保存在文件中、存储到数据库或者网络连结传输

pickle 模块
import pickle

data = ...  #Obeject
f = open('somefile','wb')
pickle.dump(data, f)

#要将对象转化为字符串,可以:
s = pickle.dumps(data)

#要从字节流重新创建出对象,可以使用pickle.load() 或者 pickle.loads()
f = open('somefile','rb')
data  = pickle.load(f)

# from a string
data = pickle.loads()

如果需要处理多个对象,可以这么做

import pickle
f = open('somedata','wb')
pickle.dump([1,2,3,4], f)
pickle.dump('hello', f)
pickle.dump({'Apple','Rear'}, f)
f.close()
f = open('somedata','rb')
>>>pickle.load(f)
...
[1, 2, 3, 4]
>>>pickle.load(f)
hello
>>>pickle.load(f)
{'Apple','Rear'}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值