Week 7
本周学习主要内容包括文件操作、正则表达式、路径操作、shutil模块
文件操作
打开操作
open(
file,
mode='r',
buffering=-1,
encoding=None,
errors=None,
newline=None,
closefd=True,
opener=None,
)
mode:
-
mode = r:(read / readonly)
只读,默认打开模式
文件不存在,立即报错 -
mode = w:(write / writeonly)
只写,不支持读取
文件存在,文件内容将被立即清空,从头写
小心内容将被清空!
文件不存在,文件将被创建,从头写
w模式为一张白纸,从头写 -
mode = a: (append)
只写,不支持读取
文件存在,追加写入
文件不存在,创建文件,(从头写)对于白纸来说也就是追加写入
a模式不管文件存在否,都从尾部写 -
mode = x:(exist)
只写,不支持读取
文件存在,抛异常 — 文件存在了
文件不存在,创建新文件
以上四种主模式只能使用一个
-
mode = t:(text)
文本模式,默认可以不写
t模式不能单独使用,必须和rwax四种模式配合使用,不影响主模式
EX:mode = ‘rt’ 只读不可写;mode = ‘wt’ 只写不可读
rt才是真正的默认模式(open中mode的缺省值) -
mode = b:(binary)
b是binary,二进制
b模式不能单独使用,必须和rwax四种之一配合使用,不影响主模式 -
mode = +:(plus)
-
+的意思是plus,附加的能力,必须和主模式配合使用,不影响主模式
-
r+ rt+ r+t 只读文本模式打开,补充写能力
-
w+ wt+ w+t 只写文本模式打开,补充读能力,w能力不变
文件指针
- 文件指针指向当前字节位置
seek:
文本模式
0 seek(0) seek(0,0) seek(x) x >= 0
1 非0 不可以用,seek(0,1)原地踏步
2 非0 不可以用,seek(0,2)相对于EOF偏移0,拉回到尾部
正则表达式
- 是文本处理极为重要的技术,用它可以对字符串按照某种规则进行检索和替换
分类
- BRE
基本正则表达式,grep、sed、vi等软件支持,vim有扩展。 - ERE
扩展正则表达式,egrep(grep-E)、sed-r等 - PCRE
几乎所有高级语言都是PCRE的方言或者变种。python使用的SRE正则表达式引擎可以认为是PCRE的子集(模块re)
基本语法
元字符:
- . :匹配除换行符外任意一个字符
- [abc]:字符集合,只能表示一个字符位置,匹配所包含的任意一个字符([abc]匹配plain中的a)
- [ ^abc ]:字符集合,只能表示一个字符位置,匹配除去集合内字符的任意一个字符
- [a-z]:字符范围,也是个集合,表示一个字符位置,匹配所包含的任意一个字符
- [ ^a-z]:字符范围,也是个集合,表示一个字符位置,匹配除去集合内字符的任意一个字符
- \b:匹配单词的边界(在文本中找到单词中开头的b字符)
- \B:不匹配单词的边界(t\B 包含t的单词但不以t结尾的字符,如write;\Bb不以b开头含b的单词,例如able)
- \d:[0-9]匹配1位数字
- \D:[ ^0-9]匹配1位非数字
- \s:匹配1位空白字符,包括换行符、制表符、空格 [\f\r\n\t\v]
- \S:匹配1位非空白字符
- \w:匹配[a-z A-Z 0-9_],包括中文的字
- \W:匹配\w之外的字符
转义:
- 凡是在正则表达式中有特殊意义的符号,如果想使用它的本意,需要用 \ 转义
- 反斜杠自身转义要使用 \
- \r、\n还是转义后代表回车、换行
重复:
- *:表示前面的正则表达式会重复0次或多次
- +:表示前面的正则表达式会重复至少1次
- ?:表示前面的正则表达式会重复0次或1次
- {n}:重复固定的n次
- {n}:重复至少n次
- n}:重复n到m次
或:
- x|y:匹配x或y
捕获:
- (pattern):使用小括号指定一个子表达式,也叫分组;捕获后会自动分配组号从1开始;可以改变优先级
- \数字:匹配对应的分组((very)\1匹配的是very very,但捕获的组group是very)
- (?:pattern):如果仅仅为了改变优先级就不需要捕获分组
- (?exp) 、(?'name’exp):命名分组捕获,但是可以通过name访问分组;python语法必须是(?Pexp)
断言:
测试字符串为 wood took foot food
零宽断言
- (?=exp):零宽度正预测先行断言;断言exp一定在匹配右边出现,也就是说断言后面一定跟exp --> f(?=oo) f后面一定有oo出现
- (?<=exp):零宽度正回顾后发断言;断言exp一定在匹配左边出现,也就是说断言前面一定有个exp前缀 --> (?<=f)ood、(?<=t)ook分别匹配ood、ook,ook前一定有t出现
负向宽度断言
贪婪与非贪婪
- 默认是贪婪模式,尽量多匹配更长的字符串
- 非贪婪很简单,再重复的符号后面加一个?问号,尽量的少匹配
引擎选项
- 默认模式:将整个测试字符串看作一个一行的大字符串
- 单行模式:将整个测试字符串看作一个一行的大字符串,. 可以匹配\n
- 多行模式:可以将一行大字符串用\n分割成多行,^指的是行首,$指的是行尾
路径操作
操作模块
- os模块常用函数 os.path模块:
from os import path
p1 = path.join('/etc','sysconfig','a/b') # -> str 拼接
p1,type(p1) #('/etc\\sysconfig\\a/b', str)
p1.split('/') #str.split 分割 ['', 'etc\\sysconfig\\a', 'b']
path.split(p1) #p1:str 一刀, rsplit,sep\ / #('/etc\\sysconfig\\a', 'b')
Path类
from pathlib import Path
初始化
Path(),Path(''),Path('.') #(WindowsPath('.'), WindowsPath('.'), WindowsPath('.'))
Path().absolute() #绝对路径
p = Path('/etc','sysconfig','c/d')
print(p) #print和p不同,但结果都是给人看的字符串
路径拼接
- 操作符 /
str / Path => Path
Path / Path => Path
Path / str => Path
str / str => Error(unsupported)
Path('a') / 'b/c' # / 运算符重载
#WindowsPath('a/b/c')
'/a' / 'b/c' / Path('d','e/f') #错的
'a' / 'b/c' / Path('d','e/f') #错的
'a' /( 'b/c' / Path('d','e/f')) #正确
'/a' /( 'b/c' / Path('d','e/f')) #正确
#WindowsPath('/a/b/c/d/e/f')
- joinpath
joinpath(*other)在当前Path路径上连接多个字符串返回新路径对象
p1 = ('/a' /( 'b/c' / Path('d','e/f')))
p1.parent.parent.joinpath('d1','d1/d2',Path('d3/d4','/d5'))
-------------------------------------------------------------
WindowsPath('/d5')
分解
- parts属性,会返回目录各部分的元组
('a' /( 'b/c' / Path('d','e/f'))).parts
#('a', 'b', 'c', 'd', 'e', 'f')
('/a' /( 'b/c' / Path('d','e/f'))).parts #最左边的 / 是根目录
#('\\', 'a', 'b', 'c', 'd', 'e', 'f')
获取路径
- str:获取路径字符串
- bytes:获取路径字符串的bytes
p,str(p),repr(p)
#(WindowsPath('/etc/sysconfig/c/d'),
#'\\etc\\sysconfig\\c\\d',
#"WindowsPath('/etc/sysconfig/c/d')")
bytes(p),str(p).encode() #等价
#(b'\\etc\\sysconfig\\c\\d', b'\\etc\\sysconfig\\c\\d')
父目录
- parent:目录的逻辑父目录
- parents:父目录惰性可迭代对象,索引0是直接的父
p1 = WindowsPath('/a/b/c/d/e/f')
p1.parent.parent #WindowsPath('/a/b/c/d')
p1.parent.parent.parent.parent.parent.parent #WindowsPath('/')
for x in p1.parents:
print(x)
-------------------------------
\a\b\c\d\e
\a\b\c\d
\a\b\c
\a\b
\a
\
list(Path('../a/b/c/d/e').parents) #路径系统当中,两个特殊目录
# . 引用,对当前目录自身的引用
# .. 对当前目录的父目录的引用
---------------------------------------------------------------
[WindowsPath('../a/b/c/d'),
WindowsPath('../a/b/c'),
WindowsPath('../a/b'),
WindowsPath('../a'),
WindowsPath('..'),
WindowsPath('.')]
目录组成部分
- name:目录的最后一个部分
- stem:目录中最后一个部分的扩展名
- suffix:目录最后一个部分,没有后缀
- name = stem + suffix
- suffixes:返回多个扩展名列表
- with_suffix(suffix):有扩展名则替换,无则补充扩展名
- with_name(name):替换目录最后一个部分并返回一个新的路径
全局方法
- cwd():返回当前工作目录
- homw():返回当前家目录
pwd #print current working path
#当前工作路径不会随着你路径的变化而变化
p1 = WindowsPath('/a/b/c/d/e/f')
p2 = Path('/data/magedu/mysql/mysql.tar.gz')
p1.cwd(),p2.cwd()
p1.home(),p2.home(),Path.home()
---------------------------------------------
(WindowsPath('C:/Users/98669/Desktop/马哥Python'),
WindowsPath('C:/Users/98669/Desktop/马哥Python'))
(WindowsPath('C:/Users/98669'),
WindowsPath('C:/Users/98669'),
WindowsPath('C:/Users/98669'))
判断方法
- exists():目录或文件是否存在(Flase – 不存在)
- is_dir():是否是目录,目录存在返回True
- is_file():是否是普通文件,文件存在返回True
- is_symlink():是否是软连接
- is_socket():是否是socket文件
- is_block_device():是否是块设备
- is_char_device():是否是字符设备
- is_absolute():是否是绝对路径
- 文件只有存在,才能知道他是什么类型
绝对路径
- resolve()非Windows,返回一个新路径,这个新路径就是当前Path对象的绝对路径,如果是软连接则直接被解析
- absolute()获取绝对路径
其他操作
- iterdir():迭代当前目录,不递归
for x in p5.parent.iterdir():
print(x)
--------------------------------
c:\temp\d1\b.txt
c:\temp\d1\d2
#p5的父目录中c:/temp下所有文件,不递归遍历,如果c:/temp有目录,判断它是否为空目录
#可以判断c:/temp所有文件的类型,dir file other
c:/temp/d1 #dir判断是否为空
c:/temp/x.txt
- mkdir(mode=0o777, parents=False, exist_ok=False):
parents – 是否创建父目录,True等同于mkdir -p;False时,父目录不存在,则抛出FileNotFoundError
exist_ok – 参数,在3.5版本加入。False时,路径存在,抛出FileExistError;True时,FileExistsError被忽略
通配符(不是正则表达式)
- glob(pattern):通配给定的模式,返回生成器对象
- rglob(pattern):通配给定的模式,递归目录,返回生成器对象
- ?:代表一个字符
- *:代表任意个字符
- [abc]或[a-z]:表示一个字符
p6 = Path('c:/temp')
list(p6.glob('*')) #当前目录下所有文件
list(p6.glob('*.py')) #当前目录下的所有.py结尾的文件(没有即返回一个空列表)
list(p6.glob('**/*.py')) #**/ 代表当前目录下的任意次目录下的*.py
list(p6.glob('**/?.py')) # ** / 代表当前目录下的任意次目录下的?.py (?一个 *任意个)
shutil模块
文件拷贝:由源文件读取内容,写入目标文件来完成拷贝过程,但这样会丢失stat数据信息(权限等,因为根本没有将这些信息复制过去),因为引出Python中一个库shutil(高级文件操作)
copy 复制
#1
copyfileobj(fsrc,fdst[,length])
#2
copyfile(src,dst,*,follow_symlinks=True)
#3
copymode(src,dst,*,follow_symlinks=True)
#4
copystat(src,dst,*,follow_symlinks=True)
#5
copy(src,dst,*,follow_symlinks=True)
#6
copy2
#7
copytree(src,dst,symlinks=False,ignore=None,copy_function=copy2,ignore_dangling_symlinks=False)
- 文件对象的复制,fsrc和fdst是open打开的文件对象,复制内容。fdst要求可以写,length指定了表示buffer大小
- 复制文件内容,不含元数据,src、dst为文件的路径字符串,本质上调用的就是copyfileobj,所以不带元数据二进制内容复制
- 仅仅复制权限
- 复制元数据,stat包含权限
- 复制文件内容、权限和部分元数据,不包括创建时间和修改时间,本质上调用了#2、#3
- 比copy多了复制全部元数据,但需要平台支持,本质上调用了#2、#4
- 递归复制目录,默认使用copy2,也就是带更多元数据复制。src、dst必须是目录,src必须存在,dst必须不存在
ignore = func,提供一个callable(src,name) -> ignored_names,提供一个函数,它会被调用。src是源目录,names是os.listdir(src)的结果,就是列出src中的文件名,返回值是要被过滤的文件名的set类型数据。
rm 删除
- shutil.rmtree(path,ignore_errors=False,οnerrοr=None)
- 递归删除,和rm -rf一样危险,慎用!!!
- 他不是原子操作,有可能删除错误就会中断,已经删除的就删除了
- ignore_error = True,会忽略错误,如果=False或者omitted是onerror生效
- onerror是callable,接收函数function、path和execinfo
move 移动
- move(src,dst,copy_function=copy2)
- 递归移动文件、目录到目标,返回目标
- 本身是用的就是os.rename方法
- 如果不支持rename,如果是目录则copytree再删除源目录
- 默认使用copy2
- shutil还有打包功能,生成tar并压缩,支持zip、gz、bz、xz