文件IO
IO是输入输出的简称 输入设备将数据或程序输入到计算机
输出设备将数据或程序的处理结果展示给用户
文件IO常用操作
item item open 打开 read 读取 write 写入 close 关闭 readline 行读取 readlines 多行读取 seek 文件指针操作 tell 指针位置
打开操作
open(file:str, mode=’r’, buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) 常用参数为前四个
file 指定文件目录 只写文件表示与py文件同目录 为防止使用\出错 可写成r”C:\Users\6k\sample.txt”形式 mode rwa 分别表示只读 只写 追加 默认为t文本模式 加b表示二进制模式 buffer为缓冲 是为解决从内存写入到硬盘的速度太慢而设置的临时存储区域 encoding 表示设置被打开文件的编码 默认为当前系统编码 简体中文版Windows为 GBK 在python里称作cp936 打开最后一定记得要关闭文件
字符 解释 错误操作 存在-创建-策略 r 缺省设置,只读打开 write 文件不存在则抛FileNotFoundError异常 t 缺省设置,文本模式 w 只写打开 read 文件不存在则创建 存在则先清空内容 x 创建并只写新文件 read 不存在则创建 存在则抛FileExistsError异常 a 只写打开,文件存在则追加 read 文件不存在则创建 内容追加 b 二进制模式 + 加在rw之后,添加写入和读取功能
总结: - r为只读 wxa均为只写 - wxa都可产生新文件 - w 无论文件存在与否 都会生成全新内容的文件 - a 无论文件存在与否 都会在文件尾部追加内容 - x 必须要求文件事先不存在 再创建新文件 - 文本模式t 字符流 按某种字符编码理解 操作字符 - 二进制模式b 字节流 与字符编码无关 操作字节
文件指针
mode=r 指针在0 mode=a 指针在EOF 文件末尾 tell() 显示当前指针位置 seek(offset[,whence])
文本模式下 whence默认为0 表示从头开始 offset只能取正整数 whence=1 表示从当前位置开始 offset只能取0 原地不动 whence=2 表示从EOF开始 offset只能取0 可从任意位置移至EOF seek按照字节偏移 二进制模式下 whence默认为0 表示从头开始 offset只能取正整数 whence=1 表示从当前位置开始 offset可正可负 whence=2 表示从EOF开始 offset可正可负 二进制模式支持任意位置偏移.向后可超界,向前不能超界. seek(0) 等价于 seek(0,0) 表示将指针移至开头
buffering 缓冲区
缓存区是内存中的一段空间 一般来说是一个先进先出(FIFO)的队列,若缓冲区满了或达到阈值,数据会flush(写入)到硬盘 f.close()命令会调用flush() buffering = -1 表示使用缺省大小的缓冲
二进制模式 使用io.DEFAULT_BUFFER_SIZE设定buffer大小 默认为8192 文本模式下 终端设备为行缓存模式 其他设备为二进制缓冲策略 buffering = 0 只在二进制模式使用 表示关闭buffer buffering = 1 表示只在文本模式使用 为行缓冲模式 见到换行符就flush buffering = int(大于1) 表示使用指定大小的缓冲 buffer总结
文本模式,一般用默认缓冲大小 二进制模式是一个个字节的操作,可指定buffer大小 一般来说 默认缓冲大小已经是最优选择 除非明确知道 否则不要调整 一般情况 若明确知道要写入磁盘 可以手动flush
encoding
None表示默认编码 依赖操作系统 简体中文版windows下默认为GBK Linux下默认为UTF-8
其他参数
error 编码容错
None和strict 有编码错误就抛异常 ignore表示忽略 newline 文本模式换行符的转换
items None ” 指定合法字符 读 ‘\r’ ‘\n’ ‘\r\n’都被转化为’\n’ 不自动转化通用换行符 指定字符换行 写 ‘\n’转化为系统缺省行分隔符os.linesep ”或’\n’表示不替换 ‘\n’被替换为指定字符
closefd
关闭文件描述符 True表示关闭 False会在文件关闭后保持这个描述符 可用fileobj.fileno()查看
read(int)
读取指定数量的字符或字节 int 取负数或None表示读取到EOF
行读取
readline(size=-1)
readlines(hint=-1)
write
write(s) 把字符串s写入文件并返回字符个数 writelines(lines) 将字符串列表写入文件
上下文管理
Linux系统对文件打开数量做了限制 lsof -p 进程号| grep test | wc -l 可查看文件被同时打开了几次 ulimit -a 查看所有限制 openfile为打开文件数的限制 默认为1024 此异常因系统资源限制产生 但不易察觉 很多时候表现为OSError 因此打开的文件 用完后一定要关闭 为解决此类问题 引出上下文管理
使用with … as 关键字 上下午管理的语句块不会开辟新的作用域 with语句块执行完毕会自动关闭文件对象
with open ('test' ) as f:
print(f.read ())
文件IO类的对象 不使用时都应及时关闭以释放资源 IO被打开就会获得文件描述符. 计算机资源有限,操作系统会做限制. 除非明确知道资源情况,否则不建议提高资源限制值.
StringIO BytesIO
io模块里的类 from io import StringIO StringIO在内存中开辟的文本模式buffer 可像文件对象一样被操作 BytesIO在内存中开辟二进制模式buffer 调用close方法 此buffer会释放 getvalue()可获取全部内容 不受指针位置影响
from io import StringIO
sio=StringIO()
sio.write ('Python2018' )
sio.seek (0 )
sio.read ()
sio.getvalue()
sio.close ()
磁盘操作比内存操作慢得多 在内存充足的情况下 应减少数据落地 减少磁盘IO 可大大提高程序的运行效率
类文件对象 file-like-obj
可像文件对象一样操作 socket对象 输入输出(stdin stdout)对象都是类文件对象
目录相关操作
from os import path
p=path.join('/etc' ,'sysconfig' ,'network' ) --> '/etc\\sysconfig\\network' :str
sp=path.split(p) --> ('/etc\\sysconfig' , 'network' ):tuple
path.exists(p) --> False
path.abspath('.' ) --> 'C:\\Users\\6k' :str
python3.4以后 建议使用pathlib模块,提供Path对象来操作.包括目录和文件. 初始化
from pathlib import Path
p=Path () #p为Path 对象
p=Path ('a' ,'b' ,'c/d' )
p=Path ('/etc' )
操作符/
Path对象/Path对象 Path对象/字符串 字符串/Path对象 joinpath(*other) 连接多个字符串到Path对象
p=Path()
p1=p/'a'
p2='b' /p
p3=Path('c' )
p4=p1/p2/p3
p4.parts --> ('a' , 'b' , 'c' ):tuple
p4.joinpath('/*' ,p3,p2) --> '/*/c/b'
属性 解释 parent 逻辑父目录 parents 父目录序列(生成器) 索引0是直接父目录 suffix 目录最后一部分的扩展名 stem 目录最后一部分 无扩展名 suffixs 多个扩展名列表 with_suffix(suffix) 补充扩展名至尾部 返回新路径 扩展名存在则无效 with_name(name) 替换目录最后一部分并返回新路径 cwd() 返回当前工作目录 home() 返回家目录 is_dir() file symlink socket block_devices char_devices absolute 是否是对应文件/设备 返回布尔值 absolute() 返回绝对路径 resolve() 返回绝对路径 软链接则返回真实路径 exists() 目录或文件是否存在 rmdir() 删除空目录 未提供判断目录为空的方法 mkdir(mode=0o777,parents=False,exist_ok=False) parents:是否创建父目录 选True表示mkdir -p ; exist_ok:选True忽略FileExistsError错误 touch(mode=0o666,exist_ok=True) 创建文件 as_uri() 将路径转化为URI iterdir() 迭代当前目录(生成器)
通配符
返回生成器 glob(pattern) 通配给定的模式 rglob(pattern) 通配给定的目录 递归访问目录 list(p.glob(‘*/ .py’)) 等价于list(p.rglob(‘*.py’)) match(pattern) 匹配模式 匹配成功返回True
Path ('a/b.py' ).match('*.py' )
Out [172 ]: True
Path ('a/b/c.py' ).match('b/*.py' )
Out [173 ]: True
Path ('a/b/c.py' ).match('a/*.py' )
Out [174 ]: False
Path ('a/b/c.py' ).match('a/**.py' )
Out [175 ]: False
Path ('a/b/c.py' ).match('a/**/*.py' )
Out [176 ]: True
Path ('a/b/c.py' ).match('**/*.py' )
Out [177 ]: True
stat() 等同于stat命令 用于查看文件状态 lstat() 同stat() 若为符号链接 则显示链接本身的文件信息 read_text() 调用open 以rt方式读取对应文件 返回文本 write_text() 调用open 以wt方式写入对应文件 返回文本 类似属性还有bytes
property/method result os.name windows是nt linux是posix os.uname() *nix支持 查看内核信息 sys.platform windows是win32 linux是linux os.listdir(path:str) 返回目录内容列表 os.stat(path) 调用linux系统stat os.chmod(path,mode,*,dir_fd=None,follow_symlinks=True) os.chmod(‘test’,0o777) 需要有相应权限 os.chown(path,uid,gid) 改变文件属主属组 需要有相应权限
shutil模块 (高级文件操作)
copyfileobj(fsrc,fdst[,length])
文件对象的复制 fdst要求可写 length用于指定buffer copyfile(src,dst,*,follow_symlinks=True)
复制文件内容 不含元数据 本质上调用copyfileobj copymode(src,dst,*,follow_symlinks=True)
copystat(src,dst,*,follow_symlinks=True)
copy(src,dst,*,follow_symlinks=True)
复制内容 权限及部分元数据 不包含创建时间与修改时间 本质上调用的是copyfile 与copymode copy2 可复制所有元数据 需平台支持 调用copyfile与copystat copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, ignore_dangling_symlinks=False)
递归复制目录 默认使用copy2 src dst 必须是目录 前者必须存在 后者相反 ignore=func 提供callable(src,name) -> ignored_names:set src为源目录 names是os.listdir(src)的结果 返回值为要被过滤掉的文件名的集合 ignore函数示例
def ignore (src,names) :
ig=filter(lambda (x:x.startwith('a' ),names)
return set(ig)
rmtree(path, ignore_errors=False, οnerrοr=None)
递归删除 如同 rm -rf 慎用 不是原子操作 有可能删除错误 当ignore_errors为False或omitted时生效 onerror为callable 接受函数function path和exeinfo move(src, dst, copy_function=copy2)
递归移动文件和目录到目标 返回目标 本身使用os.rename或copytree
csv文件
csv
带有行和列的文本文件 行分隔符\r\n,末行可省略 列分隔符常为逗号或制表符 每一行称为一条记录 record 为显示以上分隔符,需用双引号 两个双引号表示转义
from pathlib import Path
p=Path('d:/py/charm/test.csv' )
parent=p.parent
if not p.exists():
parents.mkdir(parents=True )
body='''\
id,name,age,comment
1,zs,18,"i'm 18"
2,ls,20,"this is a""test"" string"
3,ww,23,"中文行换
测试"
'''
p.write_text(body)
csv模块 reader(csvfile,dialect=’excel’,**fmtparams) 返回DictReader对象 是一个行迭代器 writer(csvfile,dialect=’excel’,**fmtparams)
import csv,pathlib
p=pathlib.Path('d:/pycharm/test.csv' )
with open(str(p)) as f:
reader=csv.reader(f)
print(next(reader))
print(next(reader))
rows=([1 ,2 ,3 ,4 ],('a' ,'b' ,'c' ,'d' ),range(11 ,15 ),'efgh' ,((20 ,),(50 ,)))
row=rows[0 ]
with open(str(p),'a' ,newline='' ) as f:
writer=csv.writer(f)
writer.writerow(row)
writer.writerows(rows)
ini最早问为初始化文件,后演变为配置文件 内容如下
[DEFAULT]
a = test
[mysql]
default-character-set=utf8
a = 1000
[mysqld]
datadir =/dbserver/data
port = 33060
character-set-server=utf8
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
from configparser import ConfigParser
cfg = ConfigParser()
cfg.read(r"D:\Pycharm\test.ini" )
print(cfg.sections(),'\n' )
for k,_ in cfg.items():
print(k,cfg.items(k),'--------------' ,sep='\n' )
tmp=cfg.get('mysqld' , 'port' )
print(tmp,type(tmp))
if not cfg.has_section('test' ):
cfg.add_section('test' )
cfg.set('test' , 'tom' ,'1' )
cfg['test' ]['jerry' ] = '2'
cfg['test' ]={'1' :'500' ,'tom' :'cat' ,'jerry' :'mice' }
print(cfg.getint('test' ,'tom' ))
with open(r"D:\Pycharm\new_test.ini" ,'a' ) as f:
cfg.write(f)
序列化与反序列化
序列化serialization:将内存中的对象转化为一个个字节 (反之则叫反序列化) 持久化(persistence) :数据序列化后保存到文件
pickle库:Python的序列化与反序列化模块
Created with Raphaël 2.1.2
字节对象
字节对象
内存对象
内存对象
文件对象
文件对象
loads
Dumps
Dump
load
上面提到的dump(s)与load(s)是序列化里的通用概念 dump(s)与序列化对应,指从内存导出 load(s)与反序列化对应,指载入内存 不加s的方式,数据存入磁盘,需要数据落地.应尽量避免 加s的方式,数据不落地,一般通过网络传输
import pickle
n='pickle'
d={'a' :1 ,'b' :'asd' ,'c' :[1 ,2 ,3 ]}
l=list('123' )
i=99
with open(n,'wb' ) as f:
pickle.dump(d,f)
pickle.dump(l,f)
pickle.dump(i,f)
with open(n,'rb' ) as f:
print(f.read(),f.seek(0 ))
for _ in range(3 ):
x= pickle.load(f)
print(x,type(x))
class AAA :
def __init__ (self) :
self.tttt='abc'
def show (self) :
print('xyz' )
aaa=AAA()
sr=pickle.dumps(aaa)
print(sr)
with open('pickle_obj' ,'wb' ) as f:
pickle.dump(aaa,f)
with open ('pickle_obj' ,'rb' ) as f:
new_aaa=pickle.load(f)
new_aaa.show()
序列化后的用途
持久化(应用较少) 网络传输,收发双方需用相同的环境(自定义类双方都要定义) pickle只能保证在python语言之间传输 跨平台 跨语言的公共协议 : XML JSON Protocol_Buffer
JSON
轻量级数据交换格式.用文本格式存储与表示数据 本质上说,JSON是文本字符串 独立于编程语言,几乎所有编程语言都支持 python JSON模块
JSON数据很少落地.一般都通过网络传输,此时需考虑压缩
import json
d={1 :'s' ,'name' :'tom' ,'EDM' :['house' ,'psy' ]}
j=json.dumps(d)
print (j,type (j))#注意数据类型以及引号的变化
new_d=json.loads(j)
print (new_d,type (new_d))
python MessagePack模块
基于二进制的高效的对象序列化库 比JSON更轻巧 更快速 安装命令 : ‘pip install msgpack-python’ 导入方式 : import msgpack 兼容JSON与pickle,用法与前两者一致
正则表达式 Regular Expression
代码 说明 举例 . 匹配除换行符外任意一个字符 [abc] 匹配中括号内任意一个字符,多选一 [^abc] 匹配除去中括号内字符的任一字符 [a-z] 匹配任一小写字母 [^a-z] 匹配任一非小写字母 \b 匹配单词边界 \bc匹配c开头的单词 d\b匹配d结尾的单词 \B 对应小写字母取反 \Bc匹配含有c且不以c开头的单词 \d 等价于[0-9] \D 等价于[^0-9] \s 匹配任一空白字符(换行符 制表符 空格) 等价于[\f\r\n\t\v] \S 等价于[^\f\r\n\t\v] \w 等价于[a-zA-Z0-9_],包括中文 \W 等价于[^a-zA-Z0-9_]
代码 说明 {n} 前面的表达式重复n次 {n,} 前面的表达式至少重复n次 {n,m} 前面的表达式重复n到m次 ? 前面的表达式重复0次或1次 * 等价于{0,} + 等价于{1,}
贪婪模式
正则表达式默认为贪婪模式,会尽量匹配长的字符 在重复符号后加?则改为非贪婪模式 例如 {n,m}? 或 *? 分组(捕获)
代码 说明 举例 x|y 匹配x或y (pattern) 小括号表示分组,分组号从1开始 \分组号 匹配对应分组号的分组 (?:pattern) 只用小括号表示改变优先级,不设置分组 industr(?:y|ies)等价于industry|industries (?exp) 分组自命名 Python语法为(?Pexp)
断言
相当于将exp作为条件判断 只匹配pattern的内容 不占用分组号
代码 说明 举例 pattern(?=exp) 断言pattern右边一定出现exp f(?=oo) : f后面一定有oo (?<=exp)pattern 断言pattern左边一定出现exp (?<=oo)f : f前面一定有oo pattern(?!exp) 断言pattern右边一定不出现exp f(?!oo) : f后面一定没有oo (? 断言pattern左边一定不出现exp (?
代码 说明 举例 IgnoreCase 匹配时忽略大小写 re.I re.IGNORECASE Singleline 单行模式(把所有文本当做一行) re.S re.DOTALL Multiline 多行模式(^行首 $行尾) re.M re.MULTILINE IgnorePatternWhitespace 忽略表达式中的空白字符,使用空白字符需转义 re.X re.VERBOSE
正则表达式例子 手机号
0~999之间的数字
IP地址
(\d{1,3}\.){3}(\d{1,3}) 0~255的范围问题交给socket模块处理更合适
import socket
ipaddr=socket .inet_aton('192.168.1.001' )
Python re模块
编译
re.compline(pattern,flags) -> regex_obj 编译后下次用相同的pattern时不再编译.可提高效率 flags用于指定编译引擎 单次匹配
import re
re.match (pattern, string , flags=0 )#不编译使用,不推荐
regex=re.compline(pattern,flags) -> regex_obj
regex.match (string , pos=0 , endpos, pattern=None)
regex.search(string , pos=0 , endpos, pattern=None)
regex.fullmatch(string , pos=0 , endpos, pattern=None)
regex.findall(string, pos=0 , endpos, pattern=None) -> list
regex.findall(string, pos=0 , endpos, pattern=None) -> iterator
匹配替换
对pattern匹配到的字符串用repl替换 repl可以是str bytes function
reg.sub(repl, string , count =0 )
reg.subn(repl, string , count =0 )
import re
s ='' '01 bottle
02 bag
03 big1
100 able' ''
reg=re.compile('[\s\d]+' )
reg.split (s ) --> ['' , 'bottle' , 'bag' , 'big' , 'able' ]