• Python理论之一 —— 数据读写


    1. Excel


    from tkinter import Tk
    from time import sleep
    from tkinter.messagebox import showwarning # 用于弹出窗口
    import win32com.client as win32 # 安装模块 pypiwin32
    
    warn=lambda app:showwarning(app,'即将退出进程')
    Range=range(3,8)
    
    def excel():
        app='Excel'
        xl=win32.gencache.EnsureDispatch('%s.Application'%app) # 调度 excel 进程
        ss=xl.Workbooks.Add() # 添加一个工作表
        sh=ss.ActiveSheet # 获取一个活动的工作表
        xl.Visible=True # 显示电子表格
        sleep(1)
        sh.Cells(1,1).Value='python -to-%s Demo'%app # 在(1,1)(行,列)即 A1 写入内容
        sleep(1)
        for i in Range: # 循环在(i行,1列)中写入内容
            sh.Cells(i,1).Value='Line %d'%i
            sleep(1)
        sh.Cells(i+2,1).Value="Th-th-th-that's all folks!"
        warn(app) # 弹出退出警告框
        ss.Close(False) # 不保存并关闭应用
        xl.Application.Quit() # 退出应用
    
    if __name__=='__main__':
        Tk().withdraw() # 使用 withdraw() 方法不让 tk 顶级窗口出现
        # 如果没有事先初始化顶级窗口,那么 Tk 会为你自动创建一个,而且不会将其隐藏,这样会在你的屏幕上造成一定的干扰。
        excel()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    1.1 openpyxl 模块

    1. openpyxl 模块只支持【.xlsx / .xlsm / .xltx / .xltm】格式的文件
    2. openpyxl 模块官网

    注:一个excel文件叫一个工作簿,工作簿内的每个Sheet 叫工作表;
    在这里插入图片描述

    1.1.1 打开表格、读取/获取信息

    1.1.1.1 打开表格、获取表格内sheet名:
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename = "test.xlsx") # 打开并获取表格
    print(workbook.sheetnames) # 获取并查看表格内sheet名
    
    • 1
    • 2
    • 3
    • 4
    1.1.1.2 根据sheet名获取工作表
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename = "test.xlsx") # 打开并获取表格
    # workbook.sheetnames # 获取并查看表格内sheet名
    sheet = workbook["Sheet1"] # 获取名为"Sheet1"的工作表
    # print(sheet)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1.1.1.3 获取表格的尺寸大小:尺寸大小指excel表格中的数据有几行几列
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename = "test.xlsx") # 打开并获取表格
    # workbook.sheetnames # 获取并查看表格内sheet名
    sheet = workbook["Sheet1"] # 获取名为"Sheet1"的工作表
    print(sheet.dimensions) # 获取表格的尺寸大小
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 运行结果:
    A2:D29 # 表示该工作表从A2开始,到D29结束;
    
    • 1
    1.1.1.4 获取表格内某个格子的数据:
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename = "test.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    # print(sheet)
    cell1 = sheet["A1"] # 查看当前sheet中A1格子的内容
    cell2 = sheet["C11"] # 查看当前sheet中C11格子的内容
    print(cell1.value, cell2.value)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1.1.1.5 获取表格内某行某列的数据:
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename = "test.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    print(sheet)
    cell1 = sheet.cell(row = 1,column = 1) # 查看当前sheet中1行1列格子的内容
    cell2 = sheet.cell(row = 11,column = 3) # 查看当前sheet中11行3列格子的内容
    print(cell1.value, cell2.value)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1.1.1.6 获取某个格子的行数、列数、坐标:
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename = "test.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    print(sheet)
    cell1 = sheet["A1"]
    cell2 = sheet["C11"]
    print(cell1.value, cell1.row, cell1.column, cell1.coordinate)
    print(cell2.value, cell2.row, cell2.column, cell2.coordinate)
    """
    .row 获取某个格子的行数;
    .columns 获取某个格子的列数;
    .corordinate 获取某个格子的坐标;
    """
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    1.1.1.7 获取一系列格子的内容:

    方式一:

    from openpyxl import load_workbook
    
    workbook = load_workbook(filename = "test.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    print(sheet)
    # 获取A1到C2区域的值,按行获取,即A1,B1,C1,A2,B2,C2共6个单元格
    cell = sheet["A1:C2"]
    print(cell)
    for i in cell: # 循环打印内容
        for j in i:
            print(j.value)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    其他获取方式:

    sheet["A"]    --- 获取A列的数据
    sheet["A:C"]    --- 获取A,B,C三列的数据
    sheet[5]   --- 只获取第5行的数据
    
    • 1
    • 2
    • 3

    方式二:

    from openpyxl import load_workbook
    
    workbook = load_workbook(filename = "test.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    print(sheet)
    # 按行获取值
    for i in sheet.iter_rows(min_row=2, max_row=5, min_col=1, max_col=2): # 获取行2到行5,列1到列2内的所有内容,并以行顺序读取数据
        for j in i:
            print(j.value)
    # 按列获取值
    for i in sheet.iter_cols(min_row=2, max_row=5, min_col=1, max_col=2): # 获取行2到行5,列1到列2内的所有内容,并以列顺序读取数据
        for j in i:
            print(j.value)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述


    方式三:按行获取所有数据

    from openpyxl import load_workbook
    
    workbook = load_workbook(filename = "test.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    print(sheet)
    for i in sheet.rows: # 按行获取所有数据
            print(i)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1.1.1.8 遍历工作表
        row_max_num= sheet.max_row # 取工作表最大列数
        # print(row_max_num)
        outputCommandList = []
        for row in range(4, row_max_num + 1):
            # item = {}
    
            value1 = sheet.cell(row, 2).value
            # item[key] = sheet.cell(row, 2).value
            # if row != 1:
            if value1 == '以下空白':
                break
            outputCommandList.append(value1)
        # print(commandList)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    1.1.2 写入、修改、样式配置

    1.1.2.1 写入某单元格内容
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename = "test.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    print(sheet)
    sheet["A1"] = "2333" # 写入A1单元格内容
    
    # 写入A1单元格内容的另一种方式
    cell = sheet["A1"]
    cell.value = "2333"
    
    workbook.save(filename = "newExcelFile.xlsx") # 以特定名称保存excel文件
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    1.1.2.2 插入行数据:
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename = "test.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    print(sheet)
    data = [
        ["唐僧","男","180cm"],
        ["孙悟空","男","188cm"],
        ["猪八戒","男","175cm"],
        ["沙僧","男","176cm"],
    ]
    for row in data: # 会在表格已有的数据后面,插入这些数(按行插入)
        sheet.append(row)
    workbook.save(filename = "test.xlsx") # 保存表格
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    1.1.2.3 使用公式:
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename = "test.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    print(sheet)
    sheet["D1"] = "标准身高"
    for i in range(1,9):
        sheet["D{}".format(i)] = '=IF(RIGHT(C{},2)="cm",C{},SUBSTITUTE(C{},"m","")*100&"cm")'.format(i,i,i) # 使用函数公式,实现单位转换:将单位为m的数值转换为单位为cm的数值
    workbook.save(filename = "test.xlsx") # 保存文件
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述


    查看支持的excel函数公式:

    from openpyxl.utils import FORMULAE
    print(FORMULAE)
    
    • 1
    • 2
    1.1.2.4 插入空行、空列:
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename = "test.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    sheet.insert_cols(idx=4,amount=2) # 插入空列,即在第4列开始插入2列空列
    sheet.insert_rows(idx=5,amount=4) # 插入空行,即在第5行开始插入4行空行
    workbook.save(filename = "test.xlsx") # 保存文件
    
    # .insert_cols(idx=数字编号, amount=要插入的列数),插入的位置是在idx列数的左侧插入;
    # .insert_rows(idx=数字编号, amount=要插入的行数),插入的行数是在idx行数的下方插入;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    1.1.2.5 删除行、列:
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename = "test.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    # 删除第一列,第一行
    sheet.delete_cols(idx=1)
    sheet.delete_rows(idx=1)
    workbook.save(filename = "test.xlsx") # 保存文件
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1.1.2.6 移动单元格:
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename = "test.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    # 向左移动两列,向下移动两行
    sheet.move_range("B6:C7",rows=2,cols=2) # 移动单元格,即B6到C7的所有单元格,向右移动两个,向下移动两格
    workbook.save(filename = "test.xlsx") # 保存文件
    
    # .move_range(“数据区域”,rows=,cols=):正整数为向下或向右、负整数为向左或向上;rows表示行左右移动,cols表示列上下移动
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1.1.2.7 修改字体样式:
    from openpyxl.styles import Font
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename="test.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    cell = sheet["A1"] # 获取A1单元格内容
    font = Font(name="微软雅黑",size=20,bold=True,italic=True,color="FF0000") # color是RGB的16进制表示
    cell.font = font # 修改单元格样式
    workbook.save(filename = "test.xlsx")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    1.1.2.8 获取表格中格子的字体样式:
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename="test.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    cell = sheet["A1"] # 获取A1单元格内容
    font = cell.font # 获取表格中格子的字体样式 
    print(font.name, font.size, font.bold, font.italic, font.color)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    运行结果:

    微软雅黑 20.0 True True <openpyxl.styles.colors.Color object>
    Parameters:
    rgb='00FF0000', indexed=None, auto=None, theme=None, tint=0.0, type='rgb'
    
    Process finished with exit code 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1.1.2.9 设置对齐样式:
    from openpyxl.styles import Alignment
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename="test.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    cell = sheet["A1"] # 获取A1单元格内容
    alignment = Alignment(horizontal="center",vertical="center",text_rotation=45,wrap_text=True)
    cell.alignment = alignment # 设置单元格对齐样式
    workbook.save(filename = "test.xlsx")
    
    # Alignment(horizontal=水平对齐模式,vertical=垂直对齐模式,text_rotation=旋转角度,wrap_text=是否自动换行)
    # 水平对齐:‘distributed’,‘justify’,‘center’,‘leftfill’, ‘centerContinuous’,‘right,‘general’;
    # 垂直对齐:‘bottom’,‘distributed’,‘justify’,‘center’,‘top’;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

    1.1.2.10 设置边框样式:
    from openpyxl import load_workbook
    from openpyxl.styles import Border, Side
    
    workbook = load_workbook(filename="test.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    cell = sheet["D6"]
    side1 = Side(style="thin",color="FF0000")
    side2 = Side(style="thick",color="FFFF0000")
    border = Border(left=side1,right=side1,top=side2,bottom=side2)
    cell.border = border # 设置该单元格的边框样式
    workbook.save(filename = "test.xlsx")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    查看边框线的内置 styles:

    from openpyxl.styles import Border, Side, borders
    print(dir(borders))
    
    • 1
    • 2

    在这里插入图片描述

    1.1.2.11 设置填充样式:
    from openpyxl.styles import PatternFill,GradientFill
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename="test.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    cell_b9 = sheet["B9"]
    pattern_fill = PatternFill(fill_type="solid",fgColor="99ccff")
    cell_b9.fill = pattern_fill # 填充单元格
    cell_b10 = sheet["B10"]
    gradient_fill = GradientFill(stop=("FFFFFF","99ccff","000000"))
    cell_b10.fill = gradient_fill # 填充单元格
    workbook.save(filename = "test.xlsx")
    
    # PatternFill(fill_type=填充样式,fgColor=填充颜色)
    # GradientFill(stop=(渐变颜色1,渐变颜色2……))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述


    查看支持的单元格填充样式:

    from openpyxl.styles import PatternFill,GradientFill
    print(gradient_fill)
    
    • 1
    • 2
    1.1.2.12 设置行高和列宽:
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename="test.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    # 设置第1行的高度
    sheet.row_dimensions[1].height = 50
    # 设置B列的宽度
    sheet.column_dimensions["B"].width = 20
    workbook.save(filename = "test.xlsx")
    """
    sheet.row_dimensions.height = 50
    sheet.column_dimensions.width = 30
    这两句代码,是将整个表的行高设置为50,列宽设置为30;
    """
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    1.1.2.13 合并/取消合并单元格:
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename="test.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    sheet.merge_cells("C1:D2") # 合并C1到D2的单元格
    sheet.merge_cells(start_row=7,start_column=1,end_row=8,end_column=3)
    workbook.save(filename = "test.xlsx")
    
    # .merge_cells(待合并的格子编号)
    # .merge_cells(start_row=起始行号,start_column=起始列号,end_row=结束行号,end_column=结束列号)
    # 取消合并单元格:
    # .unmerge_cells(待合并的格子编号)
    # .unmerge_cells(start_row=起始行号,start_column=起始列号,end_row=结束行号,end_column=结束列号)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    1.1.3 工作表sheet相关操作

    1.1.3.1 创建新的sheet表格:
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename = "test.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    workbook.create_sheet("这是一个新的sheet")
    print(workbook.sheetnames)
    workbook.save(filename = "test.xlsx")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1.1.3.2 删除某个sheet表:
    workbook.remove(sheet)
    
    • 1
    1.1.3.3 复制一个sheet表到另外一张excel表
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename = "a.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    print("a.xlsx中有这几个sheet表:",workbook.sheetnames)
    sheet = workbook['姓名'] # 获取名为“姓名”的工作表
    workbook.copy_worksheet(sheet) # 复制该工作表
    workbook.save(filename = "a.xlsx") # 保存文件
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    1.1.3.4 修改sheet表的名称:
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename = "a.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    sheet.title = "这是修改后的sheet名" # 修改工作表名
    print(sheet)
    workbook.save(filename = "a.xlsx") # 保存文件
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    1.1.3.5 创建新的excel文件:
    from openpyxl import Workbook
    
    workbook = Workbook() # 获取一个表格
    sheet = workbook.active # 获取当前活动的sheet
    sheet.title = "表格1" # 修改工作表名
    workbook.save(filename = "新建的excel表格.xlsx") # 保存文件
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1.1.3.6 冻结单元格:
    from openpyxl import load_workbook
    
    workbook = load_workbook(filename = "test.xlsx") # 打开并获取表格
    sheet = workbook.active # 获取当前活动的sheet
    sheet.freeze_panes = ("A2") # 冻结首行
    workbook.save(filename = "test.xlsx") # 保存文件
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2. word


    与 Excel 相似,唯一的不同是,Excel 中是写入单元格,而在 Word 中则是在文档的文本“范围”内插入字符串。

    from tkinter import Tk
    from time import sleep
    from tkinter.messagebox import showwarning
    import win32com.client as win32
    
    warn=lambda app:showwarning(app,'即将退出进程')
    Range=range(3,8)
    
    def word():
        app='Word'
        word=win32.gencache.EnsureDispatch('%s.Application'%app) # 调度 word 进程
        doc=word.Documents.Add() # 添加一个 word 文档
        word.Visible=True # 显示该文档
        sleep(1)
    
        rng=doc.Range(0,0)
        rng.InsertAfter('Python-to-%s Test \r\n\r\n'%app)
        sleep(1)
        for i in Range:
            rng.InsertAfter('line %d\r\n'%i)
            sleep(1)
    
        rng.InsertAfter("\r\n th-th-th-that")
        warn(app) # 弹出警告框
        doc.Close(False) # 不保存并关闭
        word.Application.Quit() # 退出进程
    
    if __name__=='__main__':
        Tk().withdraw()
        word()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    3. TXT

    3.1 打开TXT 文件

    with open("data.txt", "r") as f:
    # 或
    txtfile_dataTemp = open('data360kHzRsTemp.txt.txt',mode='w')
    
    • 1
    • 2
    • 3

    其中打开方式类型如下:
    在这里插入图片描述

    3.2 读取TXT 文件内容

    假设有data.txt 文件,其内容如下:

    F: 360.00; Q: 13.335; A: 0.874; B: 148.245; C: -223.639
    set f 360
    Set F 360.00 Pass
    
    • 1
    • 2
    • 3
    • 读取TXT 内容函数如下:
    with open("data.txt", "r") as f:
    	str_testData = f.readline() # 返回字符串,读取第一行
    	# data 打印结果:
    	# 
    	# F: 360.00; Q: 13.335; A: 0.874; B: 148.245; C: -223.639
    	
    	list_testData = f.readlines() # 返回列表,读取所有行,每一行为一个列表成员
    	# 
    	# ['F: 360.00; Q: 13.335; A: 0.874; B: 148.245; C: -223.639\n', 'set f 360\n', 'Set F 360.00 Pass']
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.3 向TXT 写入内容

    txtfile_dataTemp = open('sTemp.txt',mode='w') # 打开文件
    txtfile_dataTemp.write(`2333` + '\n') # 写入内容
    
    • 1
    • 2

    3.4 关闭TXT 文件

    txtfile_dataTemp.close()
    
    • 1
  • 相关阅读:
    【原创】使用Golang的电商搜索技术架构实现
    Flink学习24:窗口的分配器
    银发经济硬战:福寿康稳步拓荒,小柏家护轻装上阵
    【word技巧】如何限制word页眉,不被他人修改
    C#sharp数据库连接字符串
    mac安装virtualenv和virtualenvwrapper
    一条通往服务器所有端口的隧道
    java并发之AQS详解(待更)
    Windows版MySql8.0安装(亲测成功!)
    数学建模-插值算法、拟合算法
  • 原文地址:https://blog.csdn.net/weixin_43559366/article/details/127919239