zoukankan      html  css  js  c++  java
  • 文件存储

    保存数据有多种方式,其中最简单、成本最低的就是将数据保存在二进制或文本文件中。这些文件主要包括XML文件、CSV文件、JSON文件等。本章详细介绍Python API读写这些文件

    一.操作文件的基本方法

    1.1打开文件

    open函数用于打开文件,通过该函数的第一个参数指定要打开的文件名(可以是相对路径,也可以是绝对路径)
    如果open函数成功打开文件,那么该函数会返回一个TextIOWrapper对象,该对象中的方法可用来操作这个被打开的文件。如果要打开的文件不存在,会抛出FileNotFoundError异常。
    open函数的第二个参数用于指定文件模式(用一个字符串表示),这里的文件模式是指操作文件的方式,如只读、写入、追加等

    功能描述
    w 写模式
    r 读模式
    x 写模式,创建一个文件,如果文件已存在,则报错
    a 追加模式
    b 二进制模式(可与其他模式结合使用)
    + 读/写模式(可与其他模式结合使用)
    其中 b 或者 + 可与其他模式结合使用需要说明下:
    • 如 rb 就表示读取一个二进制文件
    • 如w+ 表示对打开的文件可读可写
    • 如 wb+ 则表示对二进制文件可读可写,如果模式中不加 b则默认表示文本文件
      补充:a+文件可读写,如果文件不存在,会创建一个新的文件,如果文件存在,会将要写入的内容添加到原文件的最后

    1.2读文件和写文件

    TextIOWrapper对象有如下4个常用的方法
    1.write(string):像文件写入内容,该方法返回写入文件的字节数
    2.read([n]):读取文件的内容,n是一个整数,表示从文件指针指定的位置开始读取的n个字节。如果不指定n,该方法就会读取从当前位置往后的所有的字节。该方法返回读取的数据
    3.seek(n):重新设置文件指针,也就是改变文件的当前位置。使用write方法向文件写入内容后,需要调用seek(0),才能读取刚才写入的内容。这个意思就是写完马上要读的话,就要把指针移到前面去,不然读空
    4.close():关闭文件

    # 以写模式打开test1.txt文件
    f = open('./files/test1.txt','w')
    # 向test1.txt文件写入“I love ",运行结果:7
    print(f.write('I love '))
    # 向test1.txt文件写入“python",运行结果:6
    print(f.write('python'))
    # 关闭test1.txt文件
    f.close()
    # 以读模式打开test1.txt文件
    f = open('./files/test1.txt', 'r')
    # 从test1.txt文件中读取7个字节的数据,运行结果:I love
    print(f.read(7))
    # 从test1.txt文件的当前位置开始读取6个字节的数据,运行结果:python
    print(f.read(6))
    # 关闭test.txt文件
    f.close()
    try:
        # 如果test2.txt文件不存在,会抛出异常
        f = open('./files/test2.txt','r+')
    except Exception as e:
        print(e)
    # 用追加可读写模式打开test2.txt文件
    f = open('./files/test2.txt', 'a+')
    # 向test2.txt文件写入”hello“
    print(f.write('hello'))
    # 关闭test2.txt文件
    f.close()
    # 用追加可读写模式打开test2.txt文件
    
    f = open('./files/test2.txt', 'a+')
    # 读取test2.txt文件的内容,由于目前文件指针已经在文件的结尾,所以什么都不会读出来
    print(f.read())
    # 将文件指针设置到文件开始的位置
    # f.seek(0)
    # 读取文件的全部内容,运行结果:hello
    print("关闭f.seek(0)指针,看看读出什么",f.read())
    # 关闭test2.txt文件
    f.close()
    try:
        # 用写入可读写的方式打开test2.txt文件,该文件的内容会清空
        f = open('./files/test2.txt', 'w+')
        # 读取文件的全部内容,什么都没读出来
        print(f.read())
        # 向文件写入”How are you?“
        f.write('How are you?')
        # 重置文件指针到文件的开始位置
        f.seek(0)
        # 读取文件的全部内容,运行结果:How are you?
        print(f.read())
    finally:
        # 关闭test2.txt文件,建议在finally中关闭文件
        f.close()
    

    1.3读行和写行

    读写一整行是纯文本文件最常用的操作,尽管可以使用read和write方法加上行结束符来读写文件中的整行,但比较麻烦。因此,要读写一行或多行文本,建议使用readline、readlines和writelines方法。注意,并没有writeline方法,写一行文本直接使用write方法。
    readline方法用于从文件指针当前位置读取一整行文本,也就是说,遇到行结束符停止读取文本,但读取的内容包括了行结束符。
    readlines方法从文件指针当前的位置读取后面所有的数据,并将这些数据按行结束符分隔后,放到列表中返回
    writelines方法需要通过参数指定一个字符串类型的列表,该方法会将列表中的每一个元素值作为单独的一行写入文件

    import os
    # 以读写模式打开urls.txt文件
    f = open('./files/urls.txt','r+')
    # 保存当前读上来的文本
    url = ''
    while True:
        # 从urls.txt文件读一行文本
        url = f.readline()
        # 将最后的行结束符去掉
        url = url.rstrip()
        # 当读上来的是空串,结束循环
        if url == '':
            break;
        else:
            # 输出读上来的行文本
            print(url)
    print('-----------')
    # 将文件指针重新设为0
    f.seek(0)
    # 读urls.txt文件中的所有行
    print(f.readlines())
    # 向urls.txt文件中添加一个新行
    f.write('https://jiketiku.com' + os.linesep)
    #  关闭文件
    f.close()
    # 使用'a+'模式再次打开urls.txt文件
    f = open('./files/urls.txt','a+')
    # 定义一个要写入urls.txt文件的列表
    urlList = ['https://geekori.com' + os.linesep, 'https://www.google.com' + os.linesep]
    # 将urlList写入urls.txt文件
    f.writelines(urlList)
    # 关闭urls.txt文件
    f.close()
    

    二.使用FileInput对象读取文本

    如果需要读取一个非常大的文件,使用readlines函数会占用太多内存,为了解决这个问题,可以使用for循环和readline方法逐行获取,也可以使用fileinput模块中的input函数读取指定的文件
    input方法返回一个FileInput对象,FileInput对象使用的缓存机制,并不会一次性读取文件的所有内容,所以比readlines函数更节省内存资源
    本例使用fileinput.input方法读取urls.txt文件。

    import fileinput
    # 使用input方法打开urls.txt文件
    fileobj = fileinput.input('./files/urls.txt')
    # 输出fileobj的类型
    print(type(fileobj))
    # 读取urls.txt文件第1行
    print(fileobj.readline().rstrip())
    # 通过for循环输出urls.txt文件的其他行
    for line in fileobj:
        line = line.rstrip()
        # 如果file不等于空串,输出当前行号和内容
        if line != '':
            print(fileobj.lineno(),':',line)
        else:
            # 输出当前正在操作的文件名
            print(fileobj.filename())  # 必须在第1行读取后再调用,否则返回None
    
    

    三.处理XML格式的数据

    3.1读取与搜索XML文件

    读取XML文件需要导入xml.etree.ElementTree模块,并通过该模块的parse函数读取XML文件

    from xml.etree.ElementTree import parse
    # 开始分析products.xml文件,files/products.xml是要读取的XML文件的名字
    doc = parse('files/products.xml')
    # 通过XPath搜索子节点集合,然后对这个子节点集合进行迭代
    for item in doc.iterfind('products/product'):
        # 读取product节点的id子节点的值
        id = item.findtext('id')
        # 读取product节点的name子节点的值
        name = item.findtext('name')
        # 读取product节点的price子节点的值
        price = item.findtext('price')
        # 读取product节点的uuid属性的值
        print('uuid','=',item.get('uuid'))
        print('id','=',id)
        print('name', '=',name)
        print('price','=',price)
        print('-------------')
    

    3.2字典转化为XML字符串

    将字典转化为XML文件需要使用dicttoxml模块中的dicttoxml函数,在导入dicttoxml模块之前,需要先使用下面的命令安装dicttoxml模块

    pip install dicttoxml
    

    本例将字典类型变量转化为XML字符串,然后使用from xml.dom.minidom import parseString # 解析XML字符串,并用带缩进格式的形式将XML字符串写入persons.xml文件

    import dicttoxml
    from xml.dom.minidom import parseString # 解析XML字符串
    import os
    # 定义一个字典
    d = [20,'names',
         {'name':'Bill','age':30,'salary':2000},
         {'name':'王军','age':34,'salary':3000},
         {'name':'John','age':25,'salary':2500}]
    # 将字典转换为XML格式(bytes形式)
    bxml = dicttoxml.dicttoxml(d, custom_root = 'persons')
    # 将bytes形式的XML数据按utf-8编码格式解码成XML字符串
    xml = bxml.decode('utf-8')
    # 输出XML字符串
    print(xml)
    # 解析XML字符串
    dom = parseString(xml)
    # 生成带缩进格式的XML字符串
    prettyxml = dom.toprettyxml(indent = '   ')
    # 创建files目录
    os.makedirs('files', exist_ok = True)
    # 以只写和utf-8编码格式的方式打开persons.xml文件
    f = open('files/persons.xml', 'w',encoding='utf-8')
    # 将格式化的XML字符串写入persons.xml文件
    f.write(prettyxml)
    f.close()
    

    3.3XML字符串转换为字典

    需要导入xmltodict模块

    pip install xmltodict
    

    本例使用xmltodict模块的parse函数分析这个XML字符串,如果XML格式正确,parse函数会返回与该XML字符串对应的字典对象

    import xmltodict
    # 打开products.xml文件
    f = open('files/products.xml','rt',encoding="utf-8")
    # 读取products.xml文件中的所有内容
    xml = f.read()
    # 分析XML字符串,并转化为字典
    d = xmltodict.parse(xml)
    # 输出字典内容
    print(d)
    f.close()
    # pprint格式化打印出来
    import pprint
    
    pp = pprint.PrettyPrinter(indent=4)
    pp.pprint(d)
    

    四.处理JSON格式的数据

    JSON格式的数据可以保存数组和对象,JSON数组用一对中括号将数据括起来,JSON对象用一个对大括号将数据括起来。对象中的key和value之间要用冒号(:)分隔,key-value对之间用逗号(,)分隔。注意:key和字符串类型的值要用双引号括起来,不能使用单引号。

    4.1JSON字符串与字典相互转换

    将字典转换为JSON字符串需要使用json模块的dumps函数,该函数需要将字典通过参数传入,然后返回与字典对应的JSON字符串。
    将JSON字符粗转化为字典可以使用下面两种方法
    1.使用json模块的loads函数,该函数通过参数传入JSON字符串,然后返回与该JSON字符串对应的字典
    2.使用eval函数将JSON格式1字符串当做普通的Python代码执行,eval函数会直接返回与JSON格式字符串对应的字典。

    import json
    # 定义一个字典
    data = {
        'name' : 'Bill',
        'company' : 'Microsoft',
        'age' : 34
    }
    # 将字典转换为JSON字符串
    jsonStr = json.dumps(data)
    # 输出jsonStr变量的类型
    print('字典转化为json',type(jsonStr))
    # 输出JSON字符串
    print(jsonStr)
    # 将JSON字符串转换为字典
    data = json.loads(jsonStr)
    print(type(data))
    # 输出字典
    print(data)
    # 定义一个JSON字符串
    s = '''
    {
        'name' : 'Bill',
        'company' : 'Microsoft',
        'age' : 34
    }
    '''
    # 使用eval函数将JSON字符串转换为字典
    data = eval(s)
    print(type(data))
    print(data)
    # 输出字典中的key为company的值
    print(data['company'])
    # 打开products.json文件
    f = open('files/products.json','r',encoding='utf-8')
    # 读取products.json文件中的所有内容
    jsonStr = f.read()
    # 使用eval函数将JSON字符串转换为字典
    json1 = eval(jsonStr)
    # 使用loads函数将JSON字符串转换为字典
    json2 = json.loads(jsonStr)
    print(type(json1),json1) # 直接返回列表了
    print(type(json2),json2)
    print(json2[0]['name'])
    f.close()
    

    由于eval函数可以执行任何Python代码,如果JSON字符串中包含了有害的Python代码,执行JSON字符串可能会带来风险;所以尽量使用loads,不要使用eval函数

    4.2将JSON字符串转化为类实例

    loads函数不仅可以将JSON字符串转化为字典,还可以将JSON字符串转化为类实例。转换原理是通过loads函数的object_hook关键字参数指定一个类或一个回调函数。他们都会由loads函数传入由JSON字符串转化成的字典,也就是说,loads函数将JSON字符串转化为类实例本质上是先将JSON字符串转化为字典,然后再将字典转换为对象。区别是指定类时,创建类实例的任务由loads函数完成,而指定回调函数时,创建类实例的任务需要再回调函数中完成,前者更方便,后者更灵活。

    import json
    class Product:
        # d参数是要传入的字典
        def __init__(self, d):
            self.__dict__ = d
    # 打开product.json文件
    f = open('files/product.json','r')
    # 从product.json文件中读取JSON字符串
    jsonStr = f.read()
    #  通过指定类的方式将JSON字符串转换为Product对象
    my1 = json.loads(jsonStr, object_hook=Product)
    # 下面3行代码输出Product对象中相应属性的值
    print('name', '=', my1.name)
    print('price', '=', my1.price)
    print('count', '=', my1.count)
    print('-----------')
    # 定义用于将字典转换为Product对象的函数
    def json2Product(d):
        return Product(d)
    #  通过指定类回调函数的方式将JSON字符串转换为Product对象
    my2 = json.loads(jsonStr, object_hook=json2Product)
    # 下面3行代码输出Product对象中相应属性的值
    print('name', '=', my2.name)
    print('price', '=', my2.price)
    print('count', '=', my2.count)
    f.close()
    

    4.3将类实例转化为JSON字符串

    dumps函数不仅可以将字典转换为JSON字符串,还可以将类实例转化为JSON字符串。dumps函数需要通过default关键字指定一个回调函数,在转化的过程中,dumps函数会像这个回调函数传入类实例(通过dumps函数的第一个参数传入),而回调函数的任务是将传入的对象转化为字典,然后dumps函数再将字典转化为JSON字符串。
    本例中的product2Dict函数的任务就是将Product类的实例转化为字典

    import json
    class Product:
        # 通过类的构造方法初始化3个属性
        def __init__(self, name,price,count):
            self.name = name
            self.price = price
            self.count = count
    # 用于将Product类的实例转换为字典的函数
    def product2Dict(obj):
        return {
            'name': obj.name,
            'price': obj.price,
            'count': obj.count
        }
    # 创建Product类的实例
    product = Product('特斯拉',1000000,20)
    # 将Product类的实例转换为JSON字符串,ensure_ascii关键字参数的值设为True,
    # 可以让返回的JSON字符串正常显示中文
    jsonStr = json.dumps(product, default=product2Dict,ensure_ascii=False)
    print(jsonStr)
    

    4.4类实例列表与JSON字符串相互转换

    前面转换的json对象都是单个对象,弱JSON字符串是一个类实例数组,或一个类实例的列表,也可以互相转换

    import json
    class Product:
        def __init__(self, d):
            self.__dict__ = d
    
    f = open('files/products.json','r', encoding='utf-8')
    jsonStr = f.read()
    # 将JSON字符串转换为Product对象列表
    products = json.loads(jsonStr, object_hook=Product)
    # 输出Product对象列表中所有Product对象的相关属性值
    for product in products:
        print('name', '=', product.name)
        print('price', '=', product.price)
        print('count', '=', product.count)
    f.close()
    # 定义将Product对象转换为字典的函数
    def product2Dict(product):
        return {
            'name': product.name,
            'price': product.price,
            'count': product.count
            }
    # 将Product对象列表转换为JSON字符串
    jsonStr = json.dumps(products, default=product2Dict,ensure_ascii=False)
    print(jsonStr)
    
    

    4.5将JSON字符串转换为XML字符串

    将JSON字符串转换为XML字符串其实只需要做一下中转即可,也就是先将JSON字符串转为字典,然后再使用dicttoxml模块中的dicttixml函数将字典转换为XML字符串
    本例从products.json文件读取JSON字符串,并利用loads函数和dicttoxml函数,将JSON字符串转换为XML字符串

    import json
    import dicttoxml
    f = open('files/products.json','r',encoding='utf-8')
    jsonStr = f.read()
    # 将JSON字符串转换为字典
    d = json.loads(jsonStr)
    print(d)
    # 将字典转换为XML字符串
    xmlStr = dicttoxml.dicttoxml(d).decode('utf-8')
    print(xmlStr)
    f.close()
    

    五.CSV文件存储

    CSV,全称是Comma-Separated Values,中文可以称为"逗号分隔值"或“字符分隔值”,CSV文件以纯文本形式存储表格数据。该文件是一个字符序列。CSV文件比Excel文件更加简洁,Excel文件是电子表格文件,是二进制格式的文件,里面包含了文本、数值、公式,甚至是VBA代码,而CSV文件中并不包含这些内容,只包含用特定字符分隔的文本,结构清晰简单,所以在很多场景下使用CSV文件保存数据是比较方便的

    5.1写入CSV文件

    本例演示使用csv模块API将数据写入CSV文件的完整过程

    import csv
    with open('files/data0.csv','w',encoding='utf-8') as f:
        # 写入数据
        writer = csv.writer(f)
        writer.writerow(['产品ID','产品名称','生产企业','价格'])
        writer.writerow(['0001','iPhone9','Apple',9999])
        writer.writerow(['0002','特斯拉','特斯拉',12345])
        writer.writerow(['0003','荣耀手机','华为',3456])
    # 修改字段分隔符
    with open('files/data11.csv','w',encoding='utf-8') as f:
        writer = csv.writer(f,delimiter=';')
        writer.writerow(['产品ID','产品名称','生产企业','价格'])
        writer.writerow(['0001','iPhone9','Apple',9999])
        writer.writerow(['0002','特斯拉','特斯拉',12345])
        writer.writerow(['0003','荣耀手机','华为',3456])
    
    # 一次性写入多行
    with open('files/data22.csv','w',encoding='utf-8') as f:
        writer = csv.writer(f)
        writer.writerow(['产品ID','产品名称','生产企业','价格'])
        writer.writerows([['0001','iPhone9','Apple',9999],
                          ['0002', '特斯拉', '特斯拉', 12345],
                          ['0003', '荣耀手机', '华为', 3456]])
    
    # 写入字典形式的数据
    with open('files/data33.csv','w',encoding='utf-8') as f:
        fieldnames = ['产品ID','产品名称','生产企业','价格']
        writer = csv.DictWriter(f,fieldnames=fieldnames)
        writer.writeheader()
        writer.writerow({'产品ID': '0001', '产品名称': 'iPhone9', '生产企业': 'Apple', '价格': 9999})
        writer.writerow({'产品ID': '0002', '产品名称': '特斯拉', '生产企业': '特斯拉', '价格': 12345})
        writer.writerow({'产品ID': '0003', '产品名称': '荣耀手机', '生产企业': '华为', '价格': 3456})
    
    # 追加数据
    with open('files/data00.csv','a',encoding='utf-8') as f:
        fieldnames = ['产品ID','产品名称','生产企业','价格']
        writer = csv.DictWriter(f,fieldnames=fieldnames)
        writer.writerow({'产品ID': '0004', '产品名称': '量子战衣', '生产企业': '斯塔克工业', '价格': 99999999999})
    

    5.2读取CSV文件

    使用CSV模块的reader类,可以读取CSV文件。reader类的实例时可迭代的,所以可以用for循环迭代获取每一行的数据
    如果使用Pandas,通过read_csv函数同样可以读取CSV文件的内容
    本例演示使用CSV模块API读取CSV文件中数据的完整过程

    import csv
    with open('files/data.csv','r',encoding='utf-8') as f:
        reader = csv.reader(f)
        for row in reader:
            print(row)
    
    import pandas as pd
    df = pd.read_csv('files/data.csv')
    print(df)
    

    其实XML文件、JSON文件、CSV文件本质上都是纯文本文件,只是文件的数据组织形式不同。

    努力拼搏吧,不要害怕,不要去规划,不要迷茫。但你一定要在路上一直的走下去,尽管可能停滞不前,但也要走。
  • 相关阅读:
    python学习day15 内置函数
    python学习day14 生成器表达式
    python学习day13 迭代器,生成器
    python学习day12 装饰器进阶
    gulp管理angular2项目 配置文件
    angular2 基于webpack环境搭建
    jQuery dataTable 操作个人使用总结
    报错:Could not reserve enough space for object heap error
    CSS布局之圣杯布局和双飞翼布局
    CSS 之 Position定位
  • 原文地址:https://www.cnblogs.com/wkhzwmr/p/15232805.html
Copyright © 2011-2022 走看看