常用模块之 shutil,json,pickle,shelve,xml,configparser

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()
zipfile压缩解压
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()
tarfile压缩解压

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'}]
loads与dumps
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)
load与dump
import json
f = open('file','w')
json.dump({'国籍':'中国'},f)
ret = json.dumps({'国籍':'中国'})
f.write(ret+'\n')
json.dump({'国籍':'美国'},f,ensure_ascii=False)
ret = json.dumps({'国籍':'美国'},ensure_ascii=False)
f.write(ret+'\n')
f.close()
ensure_ascii关键字参数
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)
json格式化输出

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))
pickle

如果我们将一个字典或者序列化成了一个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()
View Code

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) #打印生成的格式
自己创建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"))
处理xml文件

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'))
修改

 

转载于:https://www.cnblogs.com/596014054-yangdongsheng/p/9799881.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值