第十六天python3 文件IO(二)

BytesIO操作
  io模块中的类
  from io import BytesIO
  内存中,开辟的一个二进制模式的buffer,可以像文件对象一样操作它;
  当close方法被调用的时候,这个buffer会被释放

  readable()    检查文件是否可读
  writeable()   检查文件是否可写
  seekable()   检查文件是否可以进行seek操作
  readline()     读取文件一行
  readlines()   读取文件多行
  getvalue()    无视文件指针,输出文件全部内容

from io import BytesIO
bio = BytesIO()
print(bio.readable(),bio.writable(),bio.seekable())
bio.write(b'Hello
Beijing')
bio.seek(0)
print(bio.readline())
print(bio.getvalue())
bio.close()
执行结果:
True True True
b'Hello
'
[b'Hello
', b'Beijing']
b'Hello
Beijing'

StringIO操作
一般来说,磁盘的操作比内存的操作要慢的多,内存足够的情况下,一般的优化思路是少落地,减少磁盘IO的过程,可以大大提高程序运行效率;

from io import StringIO
sio = StringIO()
print(sio.readable(),sio.writable(),sio.seekable())
sio.write('Hello
Beijing')
sio.seek(0)
print(sio.readline())
print(sio.getvalue())
sio.close()

执行结果:
True True True
Hello

Hello
Beijing

os操作

path模块

In [1]: from os import path
#返回绝对路径
In [2]: print(path.abspath('/etc/sysconfig/network-scripts/ifcfg-eth0'))
/etc/sysconfig/network-scripts/ifcfg-eth0
#返回文件名
In [3]: print(path.basename('/etc/sysconfig/network-scripts/ifcfg-eth0'))
ifcfg-eth0
#返回多个路径中共有的最长路径
In [4]: print(path.commonprefix(['/etc/sysconfig/network-scripts/ifcfg-eth0','/etc/passwd','/etc/redhat-release']))
/etc/
#返回文件路径
In [5]: print(path.dirname('/etc/sysconfig/network-scripts/ifcfg-eth0'))
/etc/sysconfig/network-scripts
#路径存在则返回True,路径不存在则返回False
In [6]: print(path.exists('/etc/sysconfig/network-scripts/ifcfg-eth0'))
True
#把path中包含‘~’的转换成用户目录
In [7]: print(path.expanduser('~'))
/root
#返回最近访问的时间(浮点型秒数)
In [8]: print(path.getatime('/etc/sysconfig/network-scripts/ifcfg-eth0'))
1534151273.6877685
#返回最近文件修改的时间
In [9]: print(path.getmtime('/etc/sysconfig/network-scripts/ifcfg-eth0'))
1561868750.23188
#返回文件创建的时间
In [10]: print(path.getctime('/etc/sysconfig/network-scripts/ifcfg-eth0'))
1561868750.23188
#返回文件的大小,如果文件不存在则返回错误
In [11]: print(path.getsize('/etc/sysconfig/network-scripts/ifcfg-eth0'))
200
#判断是否为绝对路径
In [12]: print(path.isabs('/etc/sysconfig/network-scripts/ifcfg-eth0'))
True
#判断是否为文件,非文件或者文件不存在则为False
In [13]: print(path.isfile('/network-scripts/ifcfg-eth0'))
False
#判断是否为文件,是文件则返回True
In [14]: print(path.isfile('/etc/sysconfig/network-scripts/ifcfg-eth0'))
True
#判断是否为目录
In [15]: print(path.isdir('/etc/sysconfig/network-scripts'))
True
#判断是否为软连接,是软连接则为True
In [16]: print(path.islink('/etc/sysconfig/network-scripts/ifup-isdn'))
True
#判断是否为挂载点
In [17]: print(path.ismount('/'))
True
#把目录和文件拼接成路径
In [18]: print(path.join('/etc','network','ifconfig'))
/etc/network/ifconfig
#返回软连接具体指向的文件路径(/usr/sbin/nginx -> /usr/local/openresty/nginx/sbin/nginx)
In [19]: print(path.realpath('/usr/sbin/nginx'))
/usr/local/openresty/nginx/sbin/nginx
#判断目录或者文件是否相同
In [20]: print(path.samefile('/etc/sysconfig/network-scripts/ifcfg-eth0','/etc/passwd'))
False
#把路径分割成dirname和basename,返回一个元组
In [21]: print(path.split('/etc/sysconfig/network-scripts/ifcfg-eth0'))
('/etc/sysconfig/network-scripts', 'ifcfg-eth0')
#遍历目录
In [23]: import os

In [24]: for root,dirs,files in os.walk('/etc/sysconfig/network-scripts',topdown=False):
    ...:     for name in files:
    ...:         print(path.join(root,name))
    ...:     for name in dirs:
    ...:         print(path.join(root,name))
    ...: 
/etc/sysconfig/network-scripts/route-eth0
/etc/sysconfig/network-scripts/ifup-ippp
/etc/sysconfig/network-scripts/ifup-aliases
/etc/sysconfig/network-scripts/ifdown-ippp
/etc/sysconfig/network-scripts/ifup-TeamPort
/etc/sysconfig/network-scripts/ifdown-ppp
/etc/sysconfig/network-scripts/ifup-ipv6
/etc/sysconfig/network-scripts/ifup
/etc/sysconfig/network-scripts/init.ipv6-global
/etc/sysconfig/network-scripts/ifdown-TeamPort
/etc/sysconfig/network-scripts/ifdown-ipv6
/etc/sysconfig/network-scripts/route6-eth0
/etc/sysconfig/network-scripts/ifup-Team
/etc/sysconfig/network-scripts/ifdown-isdn
/etc/sysconfig/network-scripts/ifup-ppp
In [1]: from os import path
#path.splitdrive(path)  一般在windows下,返回驱动器名和路径组成的元组
In [2]: print(path.splitdrive(b'C:UsersSunjingxueDownloads'))
(b'C:',b'\Users\Sunjingxue\Downloads')

  os.listdir('o:/temp') 返回目录内容列表
  os也有open、read、write等方法,但是太低级,建议使用内建函数open、read、write,使用方法相似;
示例:
  ln -s test t1 建立一个软连接
  os.stat(path,*,dir_fd=None,follow_symlinks=True) 本质上调用Linux系统的stat;
  path:路径的string或者bytes,或者fd文件描述符;
  follow_symlinks True返回文本本身信息,False且如果是软连接则显示软连接本身;
  os.chmod(path,mode,*,dir_fd=None,follow_symlinks=True)
  os.chmod('test',0o777)
  os.chown(path,uid,gid) 改变文件的属主、属组,但需要足够的权限;

目录操作

In [1]: from pathlib import Path
#返回当前目录下的a/b/c/d
In [3]: p = Path('a','b','c/d')  

In [4]: print(p)
a/b/c/d
#返回根下的etc目录
In [5]: p = Path('/etc')

In [6]: print(p)
/etc
#返回/etc/sys/net/ifcfg目录
In [7]: a = Path('/etc','sys','net/ifcfg')

In [8]: print(a)
/etc/sys/net/ifcfg
#返回当前目录
In [9]: print(Path())
.

路径拼接和分解

In [21]: from pathlib import Path
#初始化
In [22]: fc = Path()

In [23]: fc = fc / 'sys'

In [24]: print(fc)
sys

In [25]: fd = fc / 'network'

In [26]: print(fd)
sys/network

In [27]: fe = Path('e/f/g')

In [28]: ff = fd / fe

In [29]: print(ff)
sys/network/e/f/g
#parts属性,可以返回路径中的每一个部分
In [30]: print(ff.parts)
('sys', 'network', 'e', 'f', 'g')
#连接多个字符串到Path对象中
In [31]: print(ff.joinpath('init','httpd',Path('conf.d')))
sys/network/e/f/g/init/httpd/conf.d
In [1]: from pathlib import Path

In [2]: p = Path('/usr/local/openresty/nginx/conf/nginx.conf')
#获取目录的最后一部分
In [3]: p.name
Out[3]: 'nginx.conf'
#获取目录的最后一部分,没有扩展名
In [4]: p.stem
Out[4]: 'nginx'
#获取目录最后一部分的扩展名
In [5]: p.suffix
Out[5]: '.conf'
#替换目录中的最后一部分,并返回一个新的路径
In [6]: p.with_name('tomcat.xml')
Out[6]: PosixPath('/usr/local/openresty/nginx/conf/tomcat.xml')
#替换目录中最后一部分的扩展名,返回新的路径,扩展名存在则无效;
In [7]: p.with_suffix('.xml')
Out[7]: PosixPath('/usr/local/openresty/nginx/conf/nginx.xml')
#返回多个扩展名列表
In [8]: print(Path(str(p)+'.xml').suffixes)
['.conf', '.xml']
#给配置文件添加后缀
In [9]: print(Path(str(p)+'.xml'))
/usr/local/openresty/nginx/conf/nginx.conf.xml
In [1]: from pathlib import Path

In [2]: p = Path('/usr/local/openresty/nginx/conf/nginx.conf')

In [13]: print(p)
/usr/local/openresty/nginx/conf/nginx.conf
#返回当前工作目录
In [14]: print(p.cwd())
/root
#返回当前家目录
In [15]: print(p.home())
/root
#判断是否为目录
In [16]: print(p.is_dir())
False
#判断是否为文件
In [17]: print(p.is_file())
True
#判断是否为软链接
In [18]: print(p.is_symlink())
False
#判断是否为socket文件
In [19]: print(p.is_socket())
False
#判断是否为块设备
In [20]: print(p.is_block_device())
False
#判断是否为字符设备
In [21]: print(p.is_char_device())
False
#判断是否为绝对路径
In [22]: print(p.is_absolute())
True
In [23]: print(p.resolve())
/usr/local/openresty/nginx/conf/nginx.conf
#resolve(),返回一个新的路径,这个新路径就是当Path对象的绝对路径,如果是软链接则直接被解析
In [24]: f = Path('/usr/sbin/nginx')

In [25]: print(f.resolve())
/usr/local/openresty/nginx/sbin/nginx
#absolute() 获取绝对路径,但是推荐使用resolve()
In [26]: print(p.absolute())
/usr/local/openresty/nginx/conf/nginx.conf
#exists()判断目录或者文件是否存在
In [27]: print(p.exists())
True
#rmdir()删除空目录
In [29]: k = Path('/root/test')

In [30]: k.rmdir()

In [31]: print(k.is_dir())
False
#as_uri()将路径返回成URI
In [32]: print(p.as_uri())
file:///usr/local/openresty/nginx/conf/nginx.conf
#touch()创建一个文件
In [39]: t = Path('/root/test.txt')

In [40]: t.touch(mode=0o666,exist_ok=True)
#mkdir()创建一个目录
In [41]: m = Path('/root/testdir')

In [42]: m.mkdir(mode=0o644,parents=False,exist_ok=False)

In [43]: print(m.is_dir)
<bound method Path.is_dir of PosixPath('/root/testdir')>
#目录创建成功
In [44]: print(m.is_dir())
True
#文件创建成功
In [45]: print(t.is_file())
True
#parents,是否创建父目录,True等同于mkdir -p;False时,父目录不存在,则抛出FileNotFoundError
#exist_ok参数,在3.5版本加入,False时,路径存在,则抛出FileExistsError,True时,FileExistsError被忽略
#目录遍历示例:
In [58]: f = Path('/usr/sbin/nginx')

In [59]: print(f)
/usr/sbin/nginx

In [61]: print(f.parents[len(f.parents)-2])
/usr
#iterdir()迭代当前目录
In [65]: it = f.parents[len(f.parents)-2].iterdir()

In [66]: for i in it:
    ...:     print(i)
    ...: 
/usr/java
/usr/c6x-uclinux
/usr/avr32-linux-gnu
/usr/tilegx-linux
/usr/h8300-linux-gnu
/usr/lib
/usr/hppa64-linux-gnu
/usr/games
/usr/local

 通配符

  glob(pattern) 通配给定的模式
  rglob(pattern)通配给定的模式,递归目录
  返回一个生成器

In [1]: from pathlib import Path

In [2]: p = Path('/etc/sysconfig/network-scripts')
#返回当前目录对象下以ifcfg开头的文件
In [3]: print(list(p.glob('ifcfg*')))
[PosixPath('/etc/sysconfig/network-scripts/ifcfg-eth0'), PosixPath('/etc/sysconfig/network-scripts/ifcfg-lo'), PosixPath('/etc/sysconfig/network-scripts/ifcfg-eth0:1')]
#在root目录下创建3级目录mkdir -pv /root/1/2/3,分别在1/2/3目录下创建1.py、2.py、3.py文件
In [6]: py = Path('/root/1')
#递归所有目录,找出以.py结尾的文件,等同于rglob
In [7]: print(list(py.glob('**/*.py')))
[PosixPath('/root/1/1.py'), PosixPath('/root/1/2/2.py'), PosixPath('/root/1/2/3/3.py')]
#rglob()递归所有目录,返回一个生成器;
In [8]: print(py.rglob('*.py'))
<generator object Path.rglob at 0x7f9fc04997d8>

In [9]: print(list(py.rglob('*.py')))
[PosixPath('/root/1/1.py'), PosixPath('/root/1/2/2.py'), PosixPath('/root/1/2/3/3.py')]

匹配
match(pattern)
模式匹配,成功返回True

In [10]: print(Path('/root/1/1.py').match('*.py'))
True

In [11]: print(Path('/root/1/2/2.py').match('2/*.py'))
True

In [12]: print(Path('/root/1/2/2.py').match('1/*.py'))
False

In [13]: print(Path('/root/1/2/2.py').match('1/*/*.py'))
True

In [14]: print(Path('/root/1/2/2.py').match('/1/*/*.py'))
False

In [15]: print(Path('/root/1/2/2.py').match('root/*/*.py'))
False

In [16]: print(Path('/root/1/2/2.py').match('root/*/*/*.py'))
True

In [17]: print(Path('/root/1/2/2.py').match('root/**/*.py'))
False

In [18]: print(Path('/root/1/2/2.py').match('root/**/*/*.py'))
True

In [19]: print(Path('/root/1/2/2.py').match('**/*.py'))
True

获取文件元数据

stat() 相当于stat命令
lstat()同stat() 但如果是符号链接,则显示符号链接本身的文件信息;

In [20]: s = Path('/etc/sysconfig/network-scripts/ifcfg-eth0')
#相当于Linux的stat命令
In [21]: print(s.stat())
os.stat_result(st_mode=33188, st_ino=276105, st_dev=64769, st_nlink=1, st_uid=0, st_gid=0, st_size=200, st_atime=1534151273, st_mtime=1561868750, st_ctime=1561868750)
#这是一个软连接
In [22]: l = Path('/usr/sbin/nginx')
#软链接追踪,显示实际链接文件的信息
In [23]: print(l.stat())
os.stat_result(st_mode=33261, st_ino=666280, st_dev=64769, st_nlink=1, st_uid=0, st_gid=0, st_size=16727928, st_atime=1620292430, st_mtime=1619687027, st_ctime=1620292578)
#显示软连接本身的文件信息
In [24]: print(l.lstat())
os.stat_result(st_mode=41471, st_ino=309800, st_dev=64769, st_nlink=1, st_uid=0, st_gid=0, st_size=37, st_atime=1612773100, st_mtime=1612773100, st_ctime=1612773100)
#/usr/sbin/nginx ---> /usr/local/openresty/nginx/sbin/nginx
In [25]: ll = Path('/usr/local/openresty/nginx/sbin/nginx')
#通过23和26就可证明,当stat()获取软链接信息时,获取的是实际文件的信息
In [26]: print(ll.stat())
os.stat_result(st_mode=33261, st_ino=666280, st_dev=64769, st_nlink=1, st_uid=0, st_gid=0, st_size=16727928, st_atime=1620292430, st_mtime=1619687027, st_ctime=1620292578)

文件操作
  使用方法类似内建函数(open(mode='r',buffering= -1,encoding= None,errors=None,newline=None))返回一个文件对象;3.5后增加的新函数;
  read_bytes()
    以‘rb’读取路径对应文件,并返回二进制流;
  read_text(encoding=None,errors=None)
    以‘rt’方式读取路径对应文件,返回文本;
  read_bytes 实际调用的都是open方法;

  Path.write_bytes(data)
    以'wb'方式写入数据到路径对应文件;

  write_text(data,encoding=None,errors=None)
    以'wt'方式写入字符串到路径对应文件;

In [27]: from pathlib import Path

In [28]: t = Path('/root/1/1.py')

In [29]: t.write_bytes(b'Beijing Hello')
Out[29]: 13

In [30]: t.read_bytes()
Out[30]: b'Beijing Hello'

In [31]: t1 = Path('/root/1/2/2.py')

In [32]: t1.write_text('Hello BeiJing')
Out[32]: 13

In [33]: t1.read_text()
Out[33]: 'Hello BeiJing'

In [34]: with t1.open() as f:
    ...:     print(f.read(5))
    ...: 
Hello

shutil模块
该模块不仅仅可以复制文件内容,也可以复制文件的stat信息;还可以复制目录;
copy复制
  copyfileobj(fsrc,fdist[,length])
    文件对象的复制,fsrc和fdist是open打开的文件对象,复制内容,fdist要求可写;length指定了表示buffer的大小;

import shutil
with open('C:/Users/Sunjingxue/Downloads/test.txt','r+') as f:
    f.write('Hello
BeiJing')
    f.flush()
#此时指针是在末尾,如果不seek(0),则复制的内容是空;
    print(f.tell())
    f.seek(0)
    with open('C:/Users/Sunjingxue/Downloads/test1.txt','w') as f1:
        shutil.copyfileobj(f,f1)

  copyfile(src,dst,*,follow_symlinks=True)
    复制文件内容,不包含元数据,src、dst为文件的路径字符串,其本质上调用的就是copyfileobj,所以不带元数据内容复制;

In [1]: import shutil

In [2]: shutil.copyfile('/root/copyfile.txt','/root/copyfile01,txt')
Out[2]: '/root/copyfile01.txt'

In [4]: with open('/root/copyfile01.txt') as f:
   ...:     print(f.read())
   ...: 
Hello BeiJing

In [7]: from pathlib import Path

In [8]: print(Path('/root/copyfile.txt').stat())
os.stat_result(st_mode=33188, st_ino=407296, st_dev=64769, st_nlink=1, st_uid=0, st_gid=0, st_size=14, st_atime=1620459966, st_mtime=1620459966, st_ctime=1620460023)

In [10]: print(Path('/root/copyfile01,txt').stat())
os.stat_result(st_mode=33188, st_ino=403577, st_dev=64769, st_nlink=1, st_uid=0, st_gid=0, st_size=14, st_atime=1620460037, st_mtime=1620460037, st_ctime=1620460037)

  copymode(src,dst,*,follow_symlinks=True)
    仅仅复制权限;

In [1]: from pathlib import Path
#copyfile.txt的权限是33279,转换成8进制就是777;
In [2]: print(Path('/root/copyfile.txt').stat())
os.stat_result(st_mode=33279, st_ino=407296, st_dev=64769, st_nlink=1, st_uid=0, st_gid=0, st_size=14, st_atime=1620459966, st_mtime=1620459966, st_ctime=1620461219)
#copyfile01.txt的权限是33188,转换成8进制就是644
In [3]: print(Path('/root/copyfile01.txt').stat())
os.stat_result(st_mode=33188, st_ino=403577, st_dev=64769, st_nlink=1, st_uid=0, st_gid=0, st_size=14, st_atime=1620461057, st_mtime=1620461057, st_ctime=1620461095)

In [4]: import shutil
#仅复制权限
In [5]: shutil.copymode('/root/copyfile.txt','/root/copyfile01.txt')
#执行完成后copyfile01.txt的权限也哼33279了;
In [6]: print(Path('/root/copyfile01.txt').stat())
os.stat_result(st_mode=33279, st_ino=403577, st_dev=64769, st_nlink=1, st_uid=0, st_gid=0, st_size=14, st_atime=1620461057, st_mtime=1620461057, st_ctime=1620461474)

In [7]: oct(33279)
Out[7]: '0o100777'

  copystat(src,dst,*,follow_symlinks=True)
    复制元数据,stat包含权限,不复制文件内容;

In [1]: from pathlib import Path

In [2]: print(Path('/root/copyfile.txt').stat())
os.stat_result(st_mode=33279, st_ino=407296, st_dev=64769, st_nlink=1, st_uid=0, st_gid=0, st_size=14, st_atime=1620459966, st_mtime=1620459966, st_ctime=1620461219)

In [3]: print(Path('/root/copyfile01.txt').stat())
os.stat_result(st_mode=33188, st_ino=403577, st_dev=64769, st_nlink=1, st_uid=0, st_gid=0, st_size=0, st_atime=1620461963, st_mtime=1620461963, st_ctime=1620461963)

In [4]: import shutil

In [5]: shutil.copystat('/root/copyfile.txt','/root/copyfile01.txt')

In [6]: print(Path('/root/copyfile01.txt').stat())
os.stat_result(st_mode=33279, st_ino=403577, st_dev=64769, st_nlink=1, st_uid=0, st_gid=0, st_size=0, st_atime=1620459966, st_mtime=1620459966, st_ctime=1620462075)

  copy(src,dst,*,follow_symlinks=True)
    复制文件内容,权限和部分元数据,不包括创建时间和修改时间;本质上调用的是copyfile和copymode;
  copy2(src,dst,*,follow_symlinks=True)
    copy2比copy多了复制全部元数据,但是需要平台支持;本质上调用的是copyfile和copystat;
  copytree(src,dst,symlinks=False,ignore=None,copy_function=copy2,ignore_dangling_symlinks=False)
    递归复制目录,默认使用copy2,也就是带更多的元数据复制;src、dst必须是目录,src必须存在,dst必须不存在;
    ignore = func,提供一个callable(src,names)--->ignored_names。提供一个函数名,src是源目录,names是os.listdir(src)的结果,就是列出src中的文件名,返回值是要被过滤的文件名的set类型数据;

rm删除
  shutil.rmtree(path,ignore_errors=False,onerror=None)
    递归删除,如同rm -rf一样;
  ignore_errors为True,忽略错误;当为False或者omitted时,onerror生效;
    onerror为callable,接受函数function、path和execinfo;
move移动
  move(src,dst,copy_function=copy2)
    递归移动文件、目录到目标、返回目标;本身使用的是os.rename方法,默认使用copy2方法;

shutil还有打包功能,生成tar并压缩,支持zip、gz、bz、xz;但是该模块的打包功能还是调用的shell命令,所以实际使用的时候直接用shell命令会更方便;

原文地址:https://www.cnblogs.com/zhangzhide/p/14739117.html