社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

Python进阶之文件I/O高效处理技巧

编程派 • 7 年前 • 1144 次点击  

作者:ansheng

来源:https://blog.ansheng.me/article/advanced-python-intensive-training-of-file-i-o-efficient-handling-skills

如何读写文本文件?

实际案例

某文本文件编码格式已直(如 UTF-8,GBK,BIG5),在 python2.x 和 python3.x 中分别如何读取这些文件?

解决方案

字符串的语义发生了变化:

python2python3
strbytes
unicodestr

python2.x 写入文件前对 unicode 编码,读入文件后对二进制字符串解码

  1. >>> f = open('py2.txt', 'w')

  2. >>> s = u'你好'

  3. >>> f.write(s.encode('gbk'))

  4. >>> f.close()

  5. >>> f = open('py2.txt', 'r')

  6. >>> t = f.read()

  7. >>> print t.decode('gbk')

  8. 你好

python3.x 中 open 函数指定 t 的文本模式, encoding 指定编码格式

  1. >>> f = open('py3.txt', 'wt', encoding='utf-8')

  2. >>> f.write('你好')

  3. 2

  4. >>> f.close()

  5. >>> f = open ('py3.txt', 'rt', encoding='utf-8')

  6. >>> s = f.read()

  7. >>> s

  8. '你好'

如何设置文件的缓冲

实际案例

将文件内容写入到硬盘设备时,使用系统调用,这类 I/O 操作的时间很长,为了减少 I/O 操作的次数,文件通常使用缓冲区(有足够多的数据才进行系统调用),文件的缓存行为,分为全缓冲、行缓存、无缓冲。

如何设置 Python 中文件对象的缓冲行文?

解决方案

全缓冲: open 函数的 buffering 设置为大于 1 的整数 n,n 为缓冲区大小

  1. >>> f = open('demo2.txt', 'w', buffering=2048)

  2. >>> f.write(' ' * 1024)

  3. >>> f.write(' ' * 1023)

  4. # 大于 2048 的时候就写入文件

  5. >>> f.write('-' * 2)

  6. >>> f.close()

行缓冲: open 函数的 buffering 设置为 1

  1. >>> f = open('demo3.txt', 'w', buffering=1)

  2. >>> f.write('abcd')

  3. >>> f.write('1234')

  4. # 只要加上 n 就写入文件中

  5. >>> f.write('n')

  6. >>> f.close()

无缓冲: open 函数的 buffering 设置为 0

  1. >>> f = open( 'demo4.txt', 'w', buffering=0)

  2. >>> f.write('a')

  3. >>> f.write('b')

  4. >>> f.close()

如何将文件映射到内存?

实际案例

  1. 在访问某些二进制文件时,希望能把文件映射到内存中,可以实现随机访问.(framebuffer 设备文件)

  2. 某些嵌入式设备,寄存器呗编址到内存地址空间,我们可以映射 /dev/mem 某范围,去访问这些寄存器

  3. 如果多个进程映射到同一个文件,还能实现进程通信的目的

解决方案

使用标准库中的 mmap 模块的 mmap() 函数,它需要一个打开的文件描述符作为参数

创建如下文件

  1. [root@iZ28i253je0Z ~]# dd if=/dev/zero of=demo.bin bs=1024 count=1024

  2. 1024 0 records in

  3. 1024 0 records out

  4. 1048576 bytes (1.0 MB) copied, 0.00380084 s, 276 MB/s

  5. # 以十六进制格式查看文件内容

  6. [root@iZ28i253je0Z ~]# od -x demo.bin

  7. 0000000 0000 0000 0000 0000 0000 0000 0000 0000

  8. *

  9. 4000000

  10. >>> import mmap

  11. >>> import os

  12. >>> f = open('demo.bin','r b')

  13. # 获取文件描述符

  14. >>> f.fileno()

  15. 3

  16. >>> m = mmap.mmap(f.fileno(),0,access=mmap.ACCESS_WRITE)

  17. >>> type(m)

  18. <type 'mmap.mmap'>

  19. # 可以通过索引获取内容

  20. >>> m[0]

  21. 'x00'

  22. >>> m[10:20]

  23. 'x00x00x00x00x00x00x00x00x00x00'

  24. # 修改内容

  25. >>> m[0] = 'x88'

查看

  1. [root@iZ28i253je0Z ~]# od -x demo.bin

  2. 0000000 0088 0000 0000 0000 0000 0000 0000 0000

  3. 0000020 0000 0000 0000 0000 0000 0000 0000 0000

  4. *

  5. 4000000

修改切片

  1. >>> m[4:8] = 'xff' * 4

查看

  1. [root@iZ28i253je0Z ~]# od -x demo.bin

  2. 0000000 0088 0000 ffff ffff 0000 0000 0000 0000

  3. 0000020 0000 0000 0000 0000 0000 0000 0000 0000

  4. *

  5. 4000000

  6. >>> m = mmap.mmap(f.fileno(),mmap.PAGESIZE * 8,access=mmap.ACCESS_WRITE,offset=mmap.PAGESIZE * 4)  

  7. >>> m[:0x1000] = 'xaa' * 0x1000

查看

  1. [root@iZ28i253je0Z ~]# od -x demo.bin

  2. 0000000 0088 0000 ffff ffff 0000 0000 0000 0000

  3. 0000020 0000 0000 0000 0000 0000 0000 0000 0000

  4. *

  5. 0040000 aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa

  6. *

  7. 0050000 0000 0000 0000 0000 0000 0000 0000 0000

  8. *

  9. 4000000

如何访问文件的状态?

实际案例

在某些项目中,我们需要获得文件状态,例如:

  1. 文件的类型(普通文件、目录、符号链接、设备文件…)

  2. 文件的访问权限

  3. 文件的最后的访问/修改/节点状态更改时间

  4. 普通文件的大小 …..

解决方案

当前目录有如下文件

  1. [root@iZ28i253je0Z 2016-09-16]# ll

  2. total 4

  3. drwxr-xr-x 2 root root 4096 Sep 16 11:35 dirs

  4. -rw-r--r-- 1 root root    0 Sep 16 11:35 files

  5. lrwxrwxrwx 1 root root   37 Sep 16 11:36 lockfile -> /tmp/qtsingleapp-aegisG-46d2-lockfile

系统调用

标准库中的 os 模块下的三个系统调用 stat、 fstat、 lstat 获取文件状态

  1. >>> import os

  2. >>> s = os.stat('files')

  3. >>> s

  4. posix.stat_result(st_mode=33188, st_ino=267646, st_dev=51713L, st_nlink=1, st_uid=0, st_gid=0, st_size=0, st_atime=1473996947, st_mtime=1473996947, st_ctime=1473996947)

  5. >>> s.st_mode

  6. 33188

  7. >>> import stat

  8. # stat 有很多 S_IS..方法来判断文件的类型

  9. >>> stat.S_ISDIR(s.st_mode)

  10. False

  11. # 普通文件

  12. >>> stat.S_ISREG(s.st_mode)

  13. True

获取文件的访问权限,只要大于 0 就为真

  1. >>> s.st_mode & stat.S_IRUSR

  2. 256

  3. >>> s.st_mode & stat.S_IXGRP

  4. 0

  5. >>> s.st_mode & stat.S_IXOTH

  6. 0

获取文件的修改时间

  1. # 访问时间

  2. >>> s.st_atime

  3. 1473996947.3384445

  4. # 修改时间

  5. >>> s.st_mtime

  6. 1473996947.3384445

  7. # 状态更新时间

  8. >>> s.st_ctime

  9. 1473996947.3384445

将获取到的时间戳进行转换

  1. >>> import time

  2. >>> time.localtime(s.st_atime)

  3. time.struct_time(tm_year=2016, tm_mon=9, tm_mday=16, tm_hour=11, tm_min=35, tm_sec=47, tm_wday=4, tm_yday=260, tm_isdst=0)

获取普通文件的大小

  1. >>> s.st_size

  2. 0

快捷函数

标准库中 os.path 下的一些函数,使用起来更加简洁

文件类型判断

  1. >>> os.path.isdir('dirs')

  2. True

  3. >>> os.path.islink('lockfile')

  4. True

  5. >>> os.path.isfile('files')  

  6. True

文件三个时间

  1. >>> os.path.getatime('files')

  2. 1473996947.3384445

  3. >>> os.path.getmtime('files')

  4. 1473996947.3384445

  5. >>> os.path.getctime('files')

  6. 1473996947.3384445

获取文件大小

  1. >>> os.path.getsize('files')

  2. 0

如何使用临时文件?

实际案例

某项目中,我们从传感器采集数据,每收集到 1G 数据后,做数据分析,最终只保存分析结果,这样很大的临时数据如果常驻内存,将消耗大量内存资源,我们可以使用临时文件存储这些临时数据(外部存储)

临时文件不用命名,且关闭后会自动被删除

解决方案

使用标准库中的 tempfile 下的 TemporaryFile, NamedTemporaryFile

  1. >>> from tempfile import TemporaryFile, NamedTemporaryFile

  2. # 访问的时候只能通过对象 f 来进行访问

  3. >>> f = TemporaryFile()

  4. >>> f.write('abcdef' * 100000)

  5. # 访问临时数据

  6. >>> f.seek(0)

  7. >>> f.read(100)

  8. 'abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd'

  9. >>> ntf = NamedTemporaryFile()

  10. # 如果要让每次创建 NamedTemporaryFile() 对象时不删除文件,可以设置 NamedTemporaryFile(delete=False)

  11. >>> ntf.name

  12. # 返回当前临时文件在文件系统中的路径

  13. '/tmp/tmppNvBu2'


题图:pexels,CC0 授权。

点击阅读原文,查看更多 Python 教程和资源。


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/QBzenKezl0
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/3010
 
1144 次点击