Pyhton Cookbook学习笔记ch5_02

你发现了虫洞这里查看效果更好

5.8固定大小记录文件迭代

  • 问题:想在一个固定长度记录或者数据块的集合上迭代,而不是在一个文件中一行一行的迭代
  • 使用iter和functools.partial()
  • 说明:iter()可以接受两个参数,一个可迭代对象、一个标记值,它会创建一个迭代器,并一直调用可调用对象直到返回标记值为止
from functools import partial
RECORD_SIZE = 30
with open('data_file/test1_3.txt','rb') as f:
    records = iter(partial(f.read,RECORD_SIZE),b'') 
    for r in records:
        print(r)
b'my name is flfl\nlove python \ns'
b'ay hello\n to the world\n python'
b' nihao \n'

5.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)
    return buf
with open('data_file/test5_9.bin','wb') as f:
    f.write(b'hello world')
buf = read_into_buffer('data_file/test5_9.bin')
buf
bytearray(b'hello world')
with open('data_file/test5_09.bin','wb') as f:
    f.write(buf)
  • readinto()用来填充已经存在的缓冲区而不是为新的对象重新分配内存再返回它们。
  • 可以使用它来避免大量的内存分配操作,比如,读取一个由相同大小的记录组成的二进制文件时,可以按下面的方式写:
record_size = 32
buf = bytearray(record_size)
with open('somefile','rb') as f:
    while True:
        n = f.readinto(buf)
        if n < record_size:
            break
        pass
  • 另外,一个有趣的特性就是memoryview,他可以通过零复制的方式对已经存在的缓冲区执行切片操作,甚至还能修改内容
with open('data_file/test5_9.bin','wb') as f:
    f.write(b'hello world')
buf = read_into_buffer('data_file/test5_9.bin')
buf
bytearray(b'hello world')
m1 = memoryview(buf)
m2 = m1[-5:]
m2
<memory at 0x0138B238>
m2[:] = b'WoRld'
buf
bytearray(b'hello WoRld')

5.10内存映射的二进制文件

  • 问题:如何将一个二进制文件映射到一个可变字节数组中,以便可以随机访问或者原地修改
  • 方案:使用mmap模块来映射文件
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 = 100
with open('data_file/data','wb') as f:
    f.seek(size-1)
    f.write(b'\x00')
m = memory_map('data_file/data')
len(m)
100
m[0:10]
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
m[0]
0
m[0:11] = b'hello world'
m.close()
with open('data_file/data','rb') as f:
    print(f.read(11))
b'hello world'
  • mmap()返回的对象同样可以作为一个上下文管理器来使用,这时候底层的文件会被自动的关闭
with memory_map('data_file/data') as m:
    print(len(m))
    print(m[0:11])
100
b'hello world'
m.closed
True
  • 默认情况下,memory_map()函数打开文件的同时支持读写操作,任何修改内容都会反映到原来的文件中。如果只是想读取,可以给access参数传递mmap.ACCESS_READ
m = memory_map('data_file/data',mmap.ACCESS_READ)
m[0]= b'1'
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-25-0a339ef9efd0> in <module>()
----> 1 m[0]= b'1'


TypeError: mmap can't modify a readonly memory map.
  • 如果你想修改本地数据,但是不想将修改反映到原始文件中,可以使用mmap.ACCESS_COPY
m = memory_map('data_file/data',mmap.ACCESS_COPY)
m[10:21] = b'hello world'
m[10:21]
b'hello world'
#再次打开原文件
m = memory_map('data_file/data',mmap.ACCESS_COPY)
m[10:21]
b'd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
  • 为了最忌访问一个文件,将其映射到内存是一个高效的做法,无需打开文件执行seek(),write(),read()等操作,只需要使用切片即可
  • 一般来说,mmap()所暴露的内存看上去只是一个二进制数组对象,但是可以使用一个内存视图来解析数据
m = memory_map('data_file/data')
v = memoryview(m).cast('I')
v[0] = 7
m[:4]
b'\x07\x00\x00\x00'

5.11文件路径名的操作

  • 问题:需要使用路径名获取文件名,绝对路径
  • 方案:使用os.path
import os
path = '/Users/beazly/Data/data.csv'
# 获取路径最后的一个组成部分
os.path.basename(path)
'data.csv'
# 获取路径
os.path.dirname(path)
'/Users/beazly/Data'
# 组合路径
os.path.join('tmp','data',os.path.basename(path))
'tmp\\data\\data.csv'
# 分离文件和文件扩展名
os.path.splitext(path)
('/Users/beazly/Data/data', '.csv')

5.12测试文件是否存在

  • 问题:如何直到某个文件是否存在
  • 方案:os.path.exists()
import os
os.path.exists('data_file/test1_3.txt')
True
os.path.exists('data_file/data1')
False
  • 还可以测试文件的类型
os.path.isfile('data_file/data')
True
os.path.islink('data_file/data')
False
  • 获取元数据,比如文件大小,修改日期等
os.path.getsize('data_file/data')
100
os.path.getmtime('data_file/data')
1536028339.0008936
import time
time.ctime(os.path.getmtime('data_file/data'))
'Tue Sep  4 10:32:19 2018'

5.13获取文件夹中的文件列表

  • 问题:如何获取某个文件夹中的文件列表
  • 方案:os.listdir()
import os
names = os.listdir('data_file')
names[:4]
['.ipynb_checkpoints', 'ch2_3_test', 'ch4_02.txt', 'ch5_1.txt']
  • 如果想要过滤一些文件,可以使用os.path中的一些函数利用列表推导
import os
names = [name for name in os.listdir('data_file')
        if os.path.isfile(os.path.join('data_file',name))]
names[:4]
['ch2_3_test', 'ch4_02.txt', 'ch5_1.txt', 'ch5_2.txt']
  • 字符出的startswith()和endswith()对于过滤目录内容也很有用
txt_file = [name for name in os.listdir('data_file')
           if name.endswith('.txt')]
txt_file
['ch4_02.txt',
 'ch5_1.txt',
 'ch5_2.txt',
 'ch5_3.txt',
 'somefile.txt',
 'test1_3.txt']
  • 对于文件名的匹配还可以使用glob和fnmatch
import glob
txt_files = glob.glob('data_file/*.txt')
txt_files
['data_file\\ch4_02.txt',
 'data_file\\ch5_1.txt',
 'data_file\\ch5_2.txt',
 'data_file\\ch5_3.txt',
 'data_file\\somefile.txt',
 'data_file\\test1_3.txt']
from fnmatch import fnmatch
txt_files = [name for name in os.listdir('data_file')
            if fnmatch(name,'*.txt')]
txt_files
['ch4_02.txt',
 'ch5_1.txt',
 'ch5_2.txt',
 'ch5_3.txt',
 'somefile.txt',
 'test1_3.txt']
  • 如果还想获取其它更加具体的文件信息,可以使用os.stat()
import os
import os.path
import glob
txt_files = glob.glob('data_file/*.txt')
name_size = [(name,os.path.getsize(name),os.path.getmtime(name))
            for name in txt_files]
for name,size,mtime in name_size:
    print(name,':',size,':',mtime)
data_file\ch4_02.txt : 111 : 1535855480.2224486
data_file\ch5_1.txt : 26 : 1535961411.2705722
data_file\ch5_2.txt : 7 : 1535964523.1387627
data_file\ch5_3.txt : 3 : 1535962989.8271592
data_file\somefile.txt : 5 : 1535977584.2078972
data_file\test1_3.txt : 68 : 1535781448.546163
# 另一种方式
file_data = [(name,os.stat(name))for name in txt_files]
for name, meta in file_data:
    print(name,' ',meta.st_size,' ',meta.st_mtime)
data_file\ch4_02.txt   111   1535855480.2224486
data_file\ch5_1.txt   26   1535961411.2705722
data_file\ch5_2.txt   7   1535964523.1387627
data_file\ch5_3.txt   3   1535962989.8271592
data_file\somefile.txt   5   1535977584.2078972
data_file\test1_3.txt   68   1535781448.546163
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值