shutil
高级的文件、文件夹、压缩包 处理模块
shutil.copyfileobj(fsrc, fdst[, length]) 将文件内容拷贝到另一个文件中 import shutil shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w')) shutil.copyfile(src, dst) 拷贝文件 shutil.copyfile('f1.log', 'f2.log') #目标文件无需存在 shutil.copymode(src, dst) 仅拷贝权限。内容、组、用户均不变 shutil.copymode('f1.log', 'f2.log') #目标文件必须存在 shutil.copystat(src, dst) 仅拷贝状态的信息,包括:mode bits, atime, mtime, flags shutil.copystat('f1.log', 'f2.log') #目标文件必须存在 shutil.copy(src, dst) 拷贝文件和权限 import shutil shutil.copy('f1.log', 'f2.log') shutil.copy2(src, dst) 拷贝文件和状态信息 import shutil shutil.copy2('f1.log', 'f2.log') shutil.ignore_patterns(*patterns) shutil.copytree(src, dst, symlinks=False, ignore=None) 递归的去拷贝文件夹 import shutil shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) #目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是排除 import shutil shutil.copytree('f1', 'f2', symlinks=True, ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) ''' 通常的拷贝都把软连接拷贝成硬链接,即对待软连接来说,创建新的文件 ''' shutil.rmtree(path[, ignore_errors[, onerror]]) 递归的去删除文件 import shutil shutil.rmtree('folder1') shutil.move(src, dst) 递归的去移动文件,它类似mv命令,其实就是重命名。 shutil.move('folder1', 'folder3') shutil.make_archive(base_name, format,...) 创建压缩包并返回文件路径,例如:zip、tar 创建压缩包并返回文件路径,例如:zip、tar base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径, 如 data_bak =>保存至当前路径 如:/tmp/data_bak =>保存至/tmp/ format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar” root_dir: 要压缩的文件夹路径(默认当前目录) owner: 用户,默认当前用户 group: 组,默认当前组 logger: 用于记录日志,通常是logging.Logger对象 将 /data 下的文件打包放置当前程序目录 import shutil ret = shutil.make_archive("data_bak", 'gztar', root_dir='/data') 将 /data下的文件打包放置 /tmp/目录 import shutil ret = shutil.make_archive("/tmp/data_bak", 'gztar', root_dir='/data') 用shutil直接解压 shutil.unpack_archive("1111.zip")
shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的
import zipfile #压缩 z=zipfile.ZipFile('laxi.zip','w') #在当前目录下建立一个名为laxi的空压缩包(已经存在的话就以写入模式打开) z.write('uesr_data.json') #讲一个名为uesr_data.json的文件写入压缩包中 z.close() #解压 z=zipfile.ZipFile("laxi.zip","r") z.extractall(path=".") #解压路径为当前路径 z.close()
import tarfile # 压缩 t=tarfile.open(r'F:代码练习uesr_data.json','w') t.add('/test1/a.py',arcname='a.bak') #arcname指定存档文件中文件的替代名称。 t.add('/test1/b.py',arcname='b.bak') t.close() #解压 t=tarfile.open('/tmp/egon.tar','r') t.extractall('/egon') t.close()
json与pickle
什么叫序列化——将原本的字典、列表等内容转换成一个字符串的过程就叫做序列化
为什么不用eval反序列化
之前我们学习过用eval内置方法可以将一个字符串转成python对象,不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇到特殊类型的时候,eval就不管用了,所以eval的重点还是通常用来执行一个字符串表达式,并返回表达式的值, eval()函数十分强大,但是eval是做什么的?eval官方demo解释为:将字符串str当成有效的表达式来求值并返回计算结果。强大的函数有代价。安全性是其最大的缺点。 想象一下,如果我们从文件中读出的不是一个数据结构,而是一句"删除文件"类似的破坏性语句,那么后果实在不堪设设想。 而使用eval就要担这个风险。 所以,我们并不推荐用eval方法来进行反序列化操作(将str转换成python中的数据结构)
序列化的目的
1,持久保存状态 2,跨平台数据交互
json
如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。
JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下:
js 中的数据类型 python数据类型 的对应关系 {} 字典 [] list string "" str python里面单引号和双引号都可以,js里面只能是双引号 int/float int/float true/false True/False null None
json格式的语法规范:
最外层通常是一个字典或列表
{} or []
只要你想写一个json格式的数据 那么最外层直接写{}
字符串必须是双引号
你可以在里面套任意多的层次
json模块的核心功能 dump dumps load loads 不带s封装write 和 read,但须要一个文件句柄
import json dic = {'k1':'v1','k2':'v2','k3':'v3'} str_dic = json.dumps(dic) #序列化:将一个字典转换成一个字符串 print(type(str_dic),str_dic) #<class 'str'> {"k3": "v3", "k1": "v1", "k2": "v2"} #注意,json转换完的字符串类型的字典中的字符串是由""表示的 dic2 = json.loads(str_dic) #反序列化:将一个字符串格式的字典转换成一个字典 #注意,要用json的loads功能处理的字符串类型的字典中的字符串必须由""表示 print(type(dic2),dic2) #<class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'} list_dic = [1,['a','b','c'],3,{'k1':'v1','k2':'v2'}] str_dic = json.dumps(list_dic) #也可以处理嵌套的数据类型 print(type(str_dic),str_dic) #<class 'str'> [1, ["a", "b", "c"], 3, {"k1": "v1", "k2": "v2"}] list_dic2 = json.loads(str_dic) print(type(list_dic2),list_dic2) #<class 'list'> [1, ['a', 'b', 'c'], 3, {'k1': 'v1', 'k2': 'v2'}]
import json f = open('json_file','w') dic = {'k1':'v1','k2':'v2','k3':'v3'} json.dump(dic,f) #dump方法接收一个文件句柄,直接将字典转换成json字符串写入文件 f.close() f = open('json_file') dic2 = json.load(f) #load方法接收一个文件句柄,直接将文件中的json字符串转换成数据结构返回 f.close() print(type(dic2),dic2)
import json f = open('file','w') json.dump({'国籍':'中国'},f) ret = json.dumps({'国籍':'中国'}) f.write(ret+' ') json.dump({'国籍':'美国'},f,ensure_ascii=False) ret = json.dumps({'国籍':'美国'},ensure_ascii=False) f.write(ret+' ') f.close()
Serialize obj to a JSON formatted str.(字符串表示的json对象) Skipkeys:默认值是False,如果dict的keys内的数据不是python的基本类型(str,unicode,int,long,float,bool,None),设置为False时,就会报TypeError的错误。此时设置成True,则会跳过这类key ensure_ascii:,当它为True的时候,所有非ASCII码字符显示为uXXXX序列,只需在dump时将ensure_ascii设置为False即可,此时存入json的中文即可正常显示。) If check_circular is false, then the circular reference check for container types will be skipped and a circular reference will result in an OverflowError (or worse). If allow_nan is false, then it will be a ValueError to serialize out of range float values (nan, inf, -inf) in strict compliance of the JSON specification, instead of using the JavaScript equivalents (NaN, Infinity, -Infinity). indent:应该是一个非负的整型,如果是0就是顶格分行显示,如果为空就是一行最紧凑显示,否则会换行且按照indent的数值显示前面的空白分行显示,这样打印出来的json数据也叫pretty-printed json separators:分隔符,实际上是(item_separator, dict_separator)的一个元组,默认的就是(‘,’,’:’);这表示dictionary内keys之间用“,”隔开,而KEY和value之间用“:”隔开。 default(obj) is a function that should return a serializable version of obj or raise TypeError. The default simply raises TypeError. sort_keys:将数据根据keys的值进行排序。 To use a custom JSONEncoder subclass (e.g. one that overrides the .default() method to serialize additional types), specify it with the cls kwarg; otherwise JSONEncoder is used.
import json data = {'username':['李华','二愣子'],'sex':'male','age':16} json_dic2 = json.dumps(data,sort_keys=True,indent=2,separators=(',',':'),ensure_ascii=False) print(json_dic2)
pickle
pickle模块主要功能 dump load dumps loads
dump是序列化 load反序列化
不带s的是帮你封装write read 更方便
load函数可以多次执行 每次load 都是往后在读一个对象 如果没有了就抛出异常Ran out of input
import pickle # 用户注册后得到的数据 name = "高跟" password = "123" height = 1.5 hobby = ["吃","喝","赌","飘",{1,2,3}] with open("userdb.txt","wt",encoding="utf-8") as f: text = "|".join([name,password,str(height)]) f.write(text) pickle支持python中所有的数据类型 user = {"name":name,"password":password,"height":height,"hobby":hobby,"test":3} 序列化的过程 with open("userdb.pkl","ab") as f: userbytes = pickle.dumps(user) f.write(userbytes) 反序列化过程 with open("userdb.pkl","rb") as f: userbytes = f.read() user = pickle.loads(userbytes) print(user) print(type(user)) dump 直接序列化到文件 with open("userdb.pkl","ab") as f: pickle.dump(user,f) load 从文件反序列化 with open("userdb.pkl","rb") as f: user = pickle.load(f) print(user) print(pickle.load(f)) print(pickle.load(f)) print(pickle.load(f))
如果我们将一个字典或者序列化成了一个json存在文件里,那么java代码或者js代码也可以拿来用,但是如果我们用pickle进行序列化,其他语言就不能读
shelve
也用于序列化,它与pickle的不同之处在于 ,不需要关心文件模式什么的 类似把它当成一个字典来看待,它可以直接对数据进行修改 而不用覆盖原来的数据,而pickle 你想要修改只能 用wb模式来覆盖
import shelve user = {"name":"高根"} s = shelve.open("userdb.shv") s["user"] = user s.close() s = shelve.open("userdb.shv",writeback=True) print(s["user"]) s["user"]["age"] = 20 s.close()
xml
xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,不过在json还没诞生前,大家只能选择用xml呀,至今很多传统公司如金融行业的很多系统的接口还主要是xml。
import xml.etree.ElementTree as ElementTree (这个另起一个名字随意,看着舒服就行) 解析d.xml tree = ElementTree.parse("d.xml") print(tree) 获取根标签 rootTree = tree.getroot() 三种获取标签的方式 获取所有人的年龄 iter是用于在全文范围获取标签 for item in rootTree.iter("age"): # 一个标签三个组成部分 print(item.tag) # 标签名称 print(item.attrib) # 标签的属性 print(item.text) # 文本内容 第二种 从当前标签的子标签中找到一个名称为age的标签 如果有多个 找到的是第一个 print(rootTree.find("age").attrib) 第三种 从当前标签的子标签中找到所有名称为age的标签 print(rootTree.findall("age")) 获取单个属性 stu = rootTree.find("stu") print(stu.get("age")) print(stu.get("name")) 删除子标签 rootTree.remove(stu) 添加子标签 要先创建一个子标签 newTag = ElementTree.Element("这是新标签",{"一个属性":"值"}) rootTree.append(newTag) 另外,节点还有set(设置节点属性) 写入文件 tree.write("f.xml",encoding="utf-8")
import xml.etree.ElementTree as ET new_xml = ET.Element("namelist") name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"}) age = ET.SubElement(name,"age",attrib={"checked":"no"}) sex = ET.SubElement(name,"sex") sex.text = '33' name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"}) age = ET.SubElement(name2,"age") age.text = '19' et = ET.ElementTree(new_xml) #生成文档对象 et.write("test.xml", encoding="utf-8",xml_declaration=True) ET.dump(new_xml) #打印生成的格式
ElementTree生来就是为了处理XML,它在Python标准库中有两种实现:一种是纯Python实现的,如xml.etree.ElementTree,另一种是速度快一点的xml.etree.cElementTree。注意:尽量使用C语言实现的那种,因为它速度更快,而且消耗的内存更少。 a. 遍历根节点的下一层 b. 下标访问各个标签、属性、文本 c. 查找root下的指定标签 d. 遍历XML文件 e. 修改XML文件 #coding=utf-8 #通过解析xml文件 ''' try: import xml.etree.CElementTree as ET except: import xml.etree.ElementTree as ET 从Python3.3开始ElementTree模块会自动寻找可用的C库来加快速度 ''' import xml.etree.ElementTree as ET import os import sys ''' XML文件读取 <?xml version="1.0" encoding="utf-8"?> <catalog> <maxid>4</maxid> <login username="pytest" passwd='123456'>dasdas <caption>Python</caption> <item id="4"> <caption>测试</caption> </item> </login> <item id="2"> <caption>Zope</caption> </item> </catalog> ''' #遍历xml文件 def traverseXml(element): #print (len(element)) if len(element)>0: for child in element: print (child.tag, "----", child.attrib) traverseXml(child) #else: #print (element.tag, "----", element.attrib) if __name__ == "__main__": xmlFilePath = os.path.abspath("test.xml") print(xmlFilePath) try: tree = ET.parse(xmlFilePath) print ("tree type:", type(tree)) # 获得根节点 root = tree.getroot() except Exception as e: #捕获除与程序退出sys.exit()相关之外的所有异常 print ("parse test.xml fail!") sys.exit() print ("root type:", type(root)) print (root.tag, "----", root.attrib) #遍历root的下一层 for child in root: print ("遍历root的下一层", child.tag, "----", child.attrib) #使用下标访问 print (root[0].text) print (root[1][1][0].text) print (20 * "*") #遍历xml文件 traverseXml(root) print (20 * "*") #根据标签名查找root下的所有标签 captionList = root.findall("item") #在当前指定目录下遍历 print (len(captionList)) for caption in captionList: print (caption.tag, "----", caption.attrib, "----", caption.text) #修改xml文件,将passwd修改为999999 login = root.find("login") passwdValue = login.get("passwd") print ("not modify passwd:", passwdValue) login.set("passwd", "999999") #修改,若修改text则表示为login.text print ("modify passwd:", login.get("passwd"))
configparser
该模块适用于配置文件的格式与windows ini文件类似,可以包含一个或多个节(section),每个节可以有多个参数(键=值)。
[db] db_port = 3306 db_user = root db_host = 127.0.0.1 db_pass = xgmtest [concurrent] processor = 20 thread = 10
import configparser config=configparser.ConfigParser() config.read('a.cfg') #查看所有的标题 res=config.sections() #['section1', 'section2'] print(res) #查看标题section1下所有key=value的key options=config.options('section1') print(options) #['k1', 'k2', 'user', 'age', 'is_admin', 'salary'] #查看标题section1下所有key=value的(key,value)格式 item_list=config.items('section1') print(item_list) #[('k1', 'v1'), ('k2', 'v2'), ('user', 'egon'), ('age', '18'), ('is_admin', 'true'), ('salary', '31')] #查看标题section1下user的值=>字符串格式 val=config.get('section1','user') print(val) #egon #查看标题section1下age的值=>整数格式 val1=config.getint('section1','age') print(val1) #18 #查看标题section1下is_admin的值=>布尔值格式 val2=config.getboolean('section1','is_admin') print(val2) #True
import configparser config=configparser.ConfigParser() config.read('a.cfg',encoding='utf-8') 删除整个标题section2 config.remove_section('section2') 删除标题section1下的某个k1和k2 config.remove_option('section1','k1') config.remove_option('section1','k2') 判断是否存在某个标题 print(config.has_section('section1')) 判断标题section1下是否有user print(config.has_option('section1','')) 添加一个标题 config.add_section('egon') 在标题egon下添加name=egon,age=18的配置 config.set('egon','name','egon') config.set('egon','age',18) #报错,必须是字符串 最后将修改的内容写入文件,完成最终的修改 config.write(open('a.cfg','w'))