分享

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

 昵称16619343 2017-08-12

来源:

如何读写文本文件?

实际案例

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

解决方案

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

python2python3
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.xopen 函数指定 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 中文件对象的缓冲行文?

解决方案

全缓冲: 函数的 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

行缓冲: 函数的 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

无缓冲: 函数的 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 函数,它需要一个打开的文件描述符作为参数

创建如下文件

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

  2. 10240 records in

  3. 10240 records out

  4. 1048576 bytes (1.0 MB) copied0.00380084 s276 MB/s

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

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

  7. 000000000000000000000000000000000000000

  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,0access=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. 000000000880000000000000000000000000000

  3. 000002000000000000000000000000000000000

  4. *

  5. 4000000

修改切片

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

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

  2. 000000000880000 ffff ffff 0000000000000000

  3. 000002000000000000000000000000000000000

  4. *

  5. 4000000

  6. m = mmap.mmap(f.fileno,mmap.PAGESIZE *8access=mmap.ACCESS_WRITEoffset=mmap.PAGESIZE *4)

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

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

  2. 000000000880000 ffff ffff 0000000000000000

  3. 000002000000000000000000000000000000000

  4. *

  5. 0040000 aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa

  6. *

  7. 005000000000000000000000000000000000000

  8. *

  9. 4000000

如何访问文件的状态?

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

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

  2. 文件的访问权限

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

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

解决方案

当前目录有如下文件

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

  2. total 4

  3. drwxr-xr-x 2 root root 4096Sep1611:35 dirs

  4. -rw-r--r--1 root root 0Sep1611:35 files

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

系统调用

标准库中的 os 模块下的三个系统调用 、 fstatlstat 获取文件状态
  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 importTemporaryFileNamedTemporaryFile

  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 授权。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多