• 常用模块之 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+'
    ')
    json.dump({'国籍':'美国'},f,ensure_ascii=False)
    ret = json.dumps({'国籍':'美国'},ensure_ascii=False)
    f.write(ret+'
    ')
    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'))
    修改
  • 相关阅读:
    博客园安卓客户端合仔茶版本V4.0震撼发布
    提示功能的检索框
    .net 玩自动化浏览器
    《表单篇》DataBase之大数据量经验总结
    自定义表主键
    一次网络程序Debug过程
    关于.NET下开源及商业图像处理(PSD)组件
    利用反射从程序集dll中动态调用方法
    Linux内核源码分析方法
    wcf基础教程之 契约(合同)Contract
  • 原文地址:https://www.cnblogs.com/596014054-yangdongsheng/p/9799881.html
Copyright © 2020-2023  润新知