01. 文件操作基础

1.1 Python文件操作概述

  • Python文件操作就是指通过Python程序对文件进行读写行为。
  • Python文件操作的大致步骤:

    • 定位文件位置(利用相对路径或绝对路径)。
    • 建立程序与文件的联系通道。
    • 文件向程序中传递数据。(输入操作)
    • 程序向文件中传递数据。(输出操作)
    • 关闭程序与文件之间的联系。

      1.2 open()函数详解

      1.2.1 open()函数的作用与格式

  • Python操作文件的一种方式是使用open()函数建立文件与程序之间的通道。

  • open()函数格式:open(文件路径, 文件的操作模式, encoding=文件的编码方式)

    1.2.2 文件操作模式

  • Python通过文件的操作模式来决定对文件执行读操作还是写操作,还可以决定是交互文件的字符串内容还是字节串内容。

  • 交互字符串内容的操作模式:
    • r:只读,即只对文件进行内容读取操作。
      • 当文件联系通道建立完成后,文件中的数据就会以行为单位加载到一个迭代器中。
      • 因此对这个迭代器进行操作,实际上就是程序在读取文件。
      • r模式要求路径对应的文件必须存在。
    • w:只写【清空写】。
      • 如果路径对应的文件不存在,则会自动创建文件并写入内容;
      • 如果路径对应的文件存在,则会先清空文件内原有的所有内容,然后再将数据写入到文件内。
    • a:只写【追加写】。
      • 如果路径对应的文件不存在,则会自动创建文件并写入内容;
      • 如果路径对应的文件存在,则会在文件原有内容的末尾,追加写入新的内容。
  • 交互字节串内容的操作模式:在字符串交互操作模式后面加个b即可,如:rb、wb、ab。

    • 加b后,其工作方式与交互字符串内容的操作模式基本一致,只是交互内容从字符串变成了字节而已。
    • 当操作的内容是字节数据时(加b后),open()函数中就不需要指定encoding参数了。

      1.2.3 文件操作的编码集

  • 设置编码集主要是针对于字符串交互操作的。因为字符串需要进行编码解码操作,字节串不需要。

  • 只有给字符串指明用哪种编码集进行编解码操作,计算机在对数据进行处理时,才不容易出现乱码。

    1.3 文件读取操作

    1.3.1 实现准备

  • 实验文件:在Python源码文件同目录下创建一个Hello.txt文件,在里面写入三行你好,Python!

image.png

1.3.2 遍历迭代器方式读取数据

  • 要对文件进行操作,首先要用open()函数与文件建立通道:
    • 路径:./Hello.txt,即当前路径下的Hello.txt文件。
      • 软件工程建议使用相对路径,这样整个项目就具有较好的可移植性。
    • 操作模式:字符串交互下的只读。
    • 编码集:UTF-8 ```python file = open(“./Hello.txt”, ‘r’, encoding=”utf-8”) print(file) # <_io.TextIOWrapper name='./Hello.txt' mode='r' encoding='utf-8'>

可以看出这个file是一个迭代器类型的数据

from collections.abc import Iterator print(isinstance(file, Iterator)) # True

  1. - 连接建立后,由于是用r只读的模式与文件建立连接的,故此时文件的内容已经被读到迭代器变量file中了,对其遍历打印输出即可。
  2. - 在完成操作后,记得调用close()函数关闭文件资源。
  3. ```python
  4. # 建立文件通道并读取数据,得到的file是个迭代器。
  5. file = open("./Hello.txt", 'r', encoding="utf-8")
  6. # 遍历迭代器,输出文件内容
  7. for data in file:
  8. print(data)
  9. # 关闭文件资源
  10. file.close()
  • 输出内容: ```python 你好,Python!

你好,Python!

你好,Python!

  1. - 可以发现,输出的内容与原Hello.txt中的内容略有差异。这是因为文件中每行文件的末尾都自带了一个换行符,而`print()`函数也自带有换行符,因此每行之间就会多出一个空行来。
  2. - 此时,要解决这个问题,只需要取消print()自带的换行即可。
  3. ```python
  4. file = open("./Hello.txt", 'r', encoding="utf-8")
  5. for data in file:
  6. print(data, end="") # 指定end参数的值为空字符串,取消其换行。
  7. file.close()
  • 输出结果:
    1. 你好,Python
    2. 你好,Python
    3. 你好,Python

    1.3.3 read()方式读取数据

  • 除了用1.3.2中的迭代器方式读取数据外,还可以调用file的read()函数将文件内的内容一次性读出。

    1. file = open("./Hello.txt", 'r', encoding="utf-8")
    2. print(file.read())
    3. file.close()
    • 运行结果:
      1. 你好,Python
      2. 你好,Python
      3. 你好,Python
  • 除此之外,还可以传入一个数值类型的参数n,指定读入内容的多少。

    • r模式下表示读入n个字符。(转义符也算一个字符,如\n算一个字符)
    • rb模式下表示读入n个字节。

      1. file = open('./Hello.txt', 'r', encoding='utf-8')
      2. print(file.read(15))
      3. file.close()
    • 运行结果:

      1. 你好,Python
      2. 你好,P
      3. # 之所以只有14字符,是因为第一行的!后面还有一个\n

      1.3.4 readline()逐行读取

  • file对象.readline()可以逐行从迭代器中读取数据,即按行读取(读取时包含换行符\n)。 ```python file = open(‘./Hello.txt’, ‘r’, encoding=’utf-8’)

读取第一行

l1 = file.readline() print(l1)

读取第二行

l2 = file.readline() print(l2)

file.close()

  1. - 运行结果:
  2. ```python
  3. 你好,Python!
  4. 你好,Python!
  5. # 因为readline()读取一行时会带上行尾的换行符,而print()默认也是换行的。
  6. # 所以运行时会多一个空行。
  7. # 要正常打印只需要指定end参数为空字符""即可。

1.3.5 readlines()按行读取全文

  • file对象.readlines()readline()函数的一个扩展,它会按行读取文件中的所有行,然后将所有行数据放到一个列表中。

    1. file = open('./Hello.txt', 'r', encoding='utf-8')
    2. all_lines = file.readlines()
    3. print(all_lines) # ['你好,Python!\n', '你好,Python!\n', '你好,Python!']
    4. file.close()

    1.4 数据写入操作

    1.4.1 数据写入文件的基本流程

  • 首先用open()函数与文件建立通道,注意写操作的open()与读操作的open()有两个显著的区别:

    • 写操作的操作模式有两个:清空写入要用w,追加写入要用a。
    • 路径指向的文件可以不存在,若文件存在则直接对已经存在的目标文件进行写入操作,若文件不存在则会创建一个空文件进行写入操作。
  • 接着调用通道中的一些写入函数,将需要写入的数据写入到指定的文件中。
  • 写入操作完成后,关闭文件与程序的联系通道。

    1.4.2 write()写入单个数据

  • file对象.write(data)函数可以将指定的单个数据内容写入到指定的文件中。

  • 代码实现示例1:编写Python程序,在当前目录下创建一个HelloLinux.txt文件,并写入一行数据你好,Linux!

    1. file = open("./HelloLinux.txt", 'w', encoding="utf-8")
    2. file.write("你好,Linux!")
    3. file.close()
  • 代码实现示例2:编写Python程序,在Hello.txt内追加写入三行Hello, Python!

    1. file = open("./Hello.txt", 'a', encoding="utf-8")
    2. file.write("\nHello, Python!\nHello, Python!\nHello, Python!")
    3. file.close()

    1.4.3 writelines()写入多个数据

  • file对象.writelines(序列)函数可以将一个序列中的所有数据一次性全部写入到指定的文件中。(writelines()写入时不会给每个元素加上换行符\n

  • 示例:将0~100中所有的偶数写入到偶数.txt文件中,并且一行只写入一个数字。 ```python file = open(‘./偶数.txt’, ‘w’, encoding=’utf-8’)

准备数据。因为写操作只能写入字符,因此需要先将数值型数据转换成整型数据。

接着,因为要求每行只能写入一个数字,所以要在数字字符串的后面拼上换行符。

even = [str(i) + “\n” for i in range(100) if i % 2 == 0] print(even)

file.writelines(even) file.close()

  1. <a name="ObyUn"></a>
  2. ### 1.5 文件I/O的其他知识点
  3. <a name="ZTKtI"></a>
  4. #### 1.5.1 字节模式操作文件
  5. - 字符操作常用于输入输出文本数据,而字节操作则常针对于文件、音频、视频等的读写。
  6. - 读取操作:
  7. - 读取流程:
  8. - 建立文件通道(此时只需要指定文件路径和操作模式,不需要指定编码)。
  9. - 调用`read()`函数,读取文件中的内容。
  10. - 关闭文件通道。
  11. - 代码实现:用字节模式读取Hello.txt文件中的内容。
  12. ```python
  13. # 建立文件通道
  14. file = open("./Hello.txt", "rb")
  15. # 调用read()函数,读取文件中的内容。
  16. data = file.read()
  17. print(data) # b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8cPython\xef\xbc\x81\r\n\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8cPython\xef\xbc\x81\r\n\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8cPython\xef\xbc\x81\r\nHello, Python!\r\nHello, Python!\r\nHello, Python!'
  18. # 关闭文件通道。
  19. file.close()
  • 写入操作:

    • 写入流程:
      • 建立文件通道(此时只需要指定文件路径和操作模式,不需要指定编码)。
      • 调用write()函数,将数据写道到文件中。若这里写入的是字符数据,需要调用数据字符串的encode()函数进行编码。
      • 关闭文件通道。
    • 代码实现:用字节模式写入你好到当前目录的打招呼.txt文件中。

      1. file = open("./打招呼.txt", "wb")
      2. file.write("你好".encode("utf-8"))
      3. file.close()
    • 注意:在字节模式下用writelines()写入多个数据,且多个数据中有字符类型数据时,所有的字符类型数据都需要进行编码。 ```python file = open(‘./偶数.txt’, ‘wb’)

even = [str(i) + “\n” for i in range(100) if i % 2 == 0] even_enc = [i.encode(‘utf-8’) for i in even] # 因为列表中所有的数据都是字符数据,因此所有的数据元素都要编码 print(even_enc)

file.writelines(even_enc) file.close()

  1. <a name="LhATQ"></a>
  2. #### 1.5.2 文件复制
  3. - 文件复制的本质:在操作系统中复制一份文件分为复制和粘贴两步:
  4. - 复制:将文件中的数据及其文件名复制一份。
  5. - 粘贴:先在目标文件夹中创建一个相同文件名的文件,然后再将数据写入。
  6. - 示例:将D:\Test\1\video.mp4文件复制到D:\Test\2\new_video.mp4。(路径可以自己换成计算机中已有的文件)
  7. ```python
  8. import os # os是系统模块
  9. # 定义原路径和目标路径
  10. src_path = "D:/Test/1/video.mp4"
  11. filename = os.path.basename(src_path) # 获取完整路径中的文件名
  12. print(filename) # video.mp4
  13. dest_path = f"D:/Test/2/{filename}"
  14. # 建立文件通道
  15. sfile = open(src_path, "rb")
  16. dfile = open(dest_path, "wb")
  17. # 实现文件复制
  18. data = sfile.read()
  19. dfile.write(data)
  20. # 关闭文件通道
  21. dfile.close()
  22. sfile.close()

1.5.3 切断联系的原因

  • 在文件处理完成后,若不调用close()关闭文件通道,则在整个程序运行结束前,这个文件的访问都将一直被占用,程序中其他代码将无法对该文件进行访问与操作。
  • 示例:读取当前目录下Hello.txt文件的内容,读取完成后不关闭,并尝试直接删除它。 ```python import os

file = open(“./Hello.txt”, “r”, encoding=”utf-8”)

对Hello.txt文件的操作。

data = file.read() print(data)

此时文件使用完成后,并没有关闭通道,尝试直接删除文件,会报错。

os.remove(“./Hello.txt”) # os模块中的remove()函数用于删除指定路径的文件

  1. - 运行结果:
  2. ```python
  3. Traceback (most recent call last):
  4. File "D:\Project\Python\BaseProject\HelloWorld.py", line 10, in <module>
  5. os.remove("./Hello.txt") # os模块中的remove()函数用于删除指定路径的文件
  6. PermissionError: [WinError 32] 另一个程序正在使用此文件,进程无法访问。: './Hello.txt'
  7. 你好,Python!
  8. 你好,Python!
  9. 你好,Python!
  10. Hello, Python!
  11. Hello, Python!
  12. Hello, Python!

1.6 with语句

1.6.1 with语句介绍

  • 在前面的介绍中,用open()函数建立的文件通道需要手动调用close()函数进行关闭。
  • 在Python中,可以使用with语句建立文件通道,此时不需要手动调用close()关闭文件通道。
  • with语句语法格式:(一个with语句后面可以跟上多个open()文件通道)

    1. with open(文件路径, 操作模式, 文件编码) as file:
    2. 对文件的操作

    1.6.2 with语句使用实例—文件剪切

  • 文件剪切操作就是在完成文件复制后,将原文件删除。

  • 实例:将当前路径下的picture.jpg文件(随便放一张图片即可)剪切到当前目录下的image目录中。 ```python import os

复制文件

src_path = “./picture.jpg” filename = os.path.basename(src_path) dest_path = f”./image/{filename}” with open(src_path, “rb”) as sfile, open(dest_path, “wb”) as dfile: img_data = sfile.read() dfile.write(img_data) dfile.flush() # 刷新加速写入

删除原文件

os.remove(src_path)

  1. <a name="BRlEz"></a>
  2. ## 02. 对象序列化
  3. <a name="tJhYA"></a>
  4. ### 2.1 序列化介绍
  5. - 序列化与反序列化的概念:
  6. - 序列化:是指把对象存储到文件中的过程。
  7. - 反序列化:是指把对象从文件中读取出来的过程,即序列化的逆过程。
  8. - 1.3、1.4中介绍的读写函数无法读写字典、列表、对象等这种序列数据,因此这种读写场景就需要使用序列化与反序列化。
  9. - Python序列化工具:
  10. - Python中提供了pickle和json两个工具用于序列化列表、字典等这些序列数据。
  11. - pickle和json两个都是Python自带的工具库,无需下载,直接导入即可。
  12. <a name="amj2i"></a>
  13. ### 2.2 pickle存储与读取
  14. <a name="b9EAA"></a>
  15. #### 2.2.1 pickle介绍
  16. - pickle是按照字节格式处理数据的,因此在涉及文件I/O时,与文件建立的联系通道应该是字节模式的。
  17. - pickle有4个常用函数,主要分为两大类:
  18. - 与内存交互:`dumps()`用于把数据存储到内存中、`loads()`用于把数据从内存中读出来。
  19. - 与文件交互:`dump()`用于把数据存储到文件中、`load()`用于把数据从文件中读出来。
  20. <a name="kwQuL"></a>
  21. #### 2.2.2 dumps/loads内存中的读写(用的不多)
  22. - `pickle.dumps(序列)`可以用于将序列数据存储到内存中。
  23. ```python
  24. import pickle
  25. data = pickle.dumps([10, 20, 30, 40])
  26. print(data) # b'\x80\x04\x95\r\x00\x00\x00\x00\x00\x00\x00]\x94(K\nK\x14K\x1eK(e.'
  27. # 在内存中以字节形式存储序列
  • pickle.loads(内存变量)可以用于将内存中的字节序列数据读出来,并反序列化成正常的数据形式。 ```python import pickle

data = pickle.dumps([10, 20, 30, 40]) print(pickle.loads(data)) # [10, 20, 30, 40]

  1. <a name="UdFvJ"></a>
  2. #### 2.2.3 dump/load文件中的读写(最常用)
  3. - 两个前缀小知识:
  4. - pickle操作的是字节格式的数据,因此在建立文件联系通道时使用的是字节模式。
  5. - 存放pickle数据的文件后缀一般是`.pkl`。
  6. - `pickle.dump(序列, 文件)`可以用于将序列数据存储到指定的`.pkl`文件中。
  7. ```python
  8. import pickle
  9. data1 = [12, 34, 56, 78]
  10. data2 = {'a': 97, 'b': 98, 'c': 99}
  11. with open('./data.pkl', 'wb') as file:
  12. pickle.dump(data1, file)
  13. pickle.dump(data2, file)
  • pickle.load(文件)可以用于从指定的.pkl文件中读出字节序列数据,并反序列化成正常的数据形式。 ```python import pickle

with open(‘./data.pkl’, ‘rb’) as file: print(pickle.load(file))

  1. - 运行结果:可以发现就打印了首先写入的data1,后写入的data2并没有被读出来。
  2. ```python
  3. [12, 34, 56, 78]
  • 原因分析:
    • pickle.load(文件)在物理上是写入到磁盘的文件中,但从逻辑上它更像是将数据存储到一个队列中。
    • 跟据数据结构的知识,队列的特点是先进先出。因此data1是先写入的,故读也是先读data1;data2是后写入的,理所应当的后读data2。
    • 当队列中的内容都被读完时,队列就变成了一个空队列,此时若再进行读操作,那就会报错。 ```python import pickle

with open(‘./data.pkl’, ‘rb’) as file: print(pickle.load(file)) # [12, 34, 56, 78] print(pickle.load(file)) # {‘a’: 97, ‘b’: 98, ‘c’: 99} print(pickle.load(file)) # 队列已空,报错:EOFError: Ran out of input

  1. - 补充:
  2. - 由于pickle文件读写的这种特点,因此建议在写入多个数据前,先将所有的数据封装到一个大容器中。
  3. - 这样在读取时只用固定的读一次,即可避免因为少读造成的数据不完整以及多读的报错问题。
  4. ```python
  5. import pickle
  6. # 封装多个数据
  7. data = [
  8. [12, 34, 56, 78],
  9. {'a': 97, 'b': 98, 'c': 99}
  10. ]
  11. # 写入
  12. with open('./data.pkl', 'wb') as file:
  13. pickle.dump(data, file)
  14. # 读取
  15. with open('./data.pkl', 'rb') as file:
  16. print(pickle.load(file)) # [[12, 34, 56, 78], {'a': 97, 'b': 98, 'c': 99}]

2.3 JSON存储与读取

2.3.1 JSON介绍

  • JSON是JavaScript Object Notation — JS对象简谱的缩写,但是JSON中没有涉及到JS的语法,它只是采用了JS中数据的格式而已。
  • JSON支持的数据格式:
    • JSONArray:即JSON数组,格式为:[元素1, 元素2, …, 元素N],对应Python的列表。
    • JSONObject:即JSON对象,格式为:{Key1: Value1, Key2, Value2, …, KeyN: ValueN},对应Python的字典。
    • string:即字符串,格式为:'0个或多个字符',对应Python的字符串。
    • number:即数值类型,包含整数或者小数。对应Python的int和float。
    • boolean:即布尔类型,有true和false两个值,对应Python中的bool。
    • null:即空对象,只有一个唯一的值null,对应Python中的None。
  • JSON是一种轻量级的数据类型,并且从它的数据类型可以看出,它几乎可以兼容所有的编程语言,因此十分适合用于网络数据传输。
  • Python中的json模块就是用于操作JSON数据的,和pickle一样,josn也有4个常用函数:

    • 与内存交互:dumps()用于把数据存储到内存中、loads()用于把数据从内存中读出来。
    • 与文件交互:dump()用于把数据存储到文件中、load()用于把数据从文件中读出来。

      2.3.2 dumps/loads内存中的读写(用的不多)

  • json.dumps(obj)可以用于将对象数据obj存储到内存中。

    • JSON的数据是字符串格式的数据。
    • 在将数据转换成JSON数据时,默认对中文数据会进行Unicode编码。 ```python import json

students = [ {‘sid’: 10001, ‘name’: ‘乐乐’}, {‘sid’: 10002, ‘name’: ‘美美’} ]

json_data = json.dumps(students) print(json_data) # [{“sid”: 10001, “name”: “\u4e50\u4e50”}, {“sid”: 10002, “name”: “\u7f8e\u7f8e”}]

  1. - 若要让中文数据保存原有的样子(即不进行编码),只需要将`dumps()`函数的`ensure_ascii`参数的值设置为False即可。
  2. ```python
  3. import json
  4. students = [
  5. {'sid': 10001, 'name': '乐乐'},
  6. {'sid': 10002, 'name': '美美'}
  7. ]
  8. json_data = json.dumps(students, ensure_ascii=False)
  9. print(json_data) # [{"sid": 10001, "name": "乐乐"}, {"sid": 10002, "name": "美美"}]
  • json.loads(内存变量)可以用于将内存中的JSON数据读出来,并反序列化成正常的数据形式。
    • 注意,虽然JSON数据的字面量可能和普通数据是一样的。
    • 但是JSON一定是字符串类型的数据,而loads()出来的可能是其他类型的数据。 ```python import json

students = [ {‘sid’: 10001, ‘name’: ‘乐乐’}, {‘sid’: 10002, ‘name’: ‘美美’} ]

json_data = json.dumps(students, ensure_ascii=False) print(json_data, type(json_data)) # [{“sid”: 10001, “name”: “乐乐”}, {“sid”: 10002, “name”: “美美”}]

data = json.loads(json_data) print(data, type(data)) # [{‘sid’: 10001, ‘name’: ‘乐乐’}, {‘sid’: 10002, ‘name’: ‘美美’}]

  1. <a name="UJ9op"></a>
  2. #### 2.3.3 dump/load文件中的读写(最常用)
  3. - 两个前缀小知识:
  4. - json操作的是Unicode编码的字符串格式的数据,因此在建立文件联系通道时使用的是字符模式。
  5. - 存放JSON数据的文件后缀一般是`.json`。
  6. - `json.dump(JSON数据, 文件)`可以用于将JSON数据存储到指定的`.json`文件中。
  7. ```python
  8. import json
  9. students = [
  10. {'sid': 10001, 'name': '乐乐'},
  11. {'sid': 10002, 'name': '美美'}
  12. ]
  13. json_data = json.dumps(students, ensure_ascii=False)
  14. with open('./data.json', 'w', encoding='utf-8') as file:
  15. json.dump(students, file, ensure_ascii=False)
  • json.load(文件)可以用于从指定的.json文件中读出JSON数据,并反序列化成正常的数据形式。 ```python import json

with open(‘./data.json’, ‘r’, encoding=’utf-8’) as file: data = json.load(file) print(data, type(data)) # [{‘sid’: 10001, ‘name’: ‘乐乐’}, {‘sid’: 10002, ‘name’: ‘美美’}]

  1. <a name="ut5wI"></a>
  2. ## 03. Python操作Excel、CSV
  3. <a name="yRFZ4"></a>
  4. ### 3.1 CSV文件操作
  5. <a name="rrfPR"></a>
  6. #### 3.1.1 CSV介绍
  7. - CSV的文件结构与Excel的文件结构十分类似,都是一行一行来存储信息的。
  8. - Excel里一行中不同列的数据之间是以不同的单元格来区分的,而CSV则是用逗号分割的,因此CSV也称为逗号分隔值文件。
  9. - CSV是一种纯文本文件,几乎所有的编程语言都是支持与纯文本文件进行交互,所以CSV的支持性比Excel好,但是在其他领域中Excel的占比是比较高的,因此CSV一般作为数据库、Excel表格数据导入导出的数据交换文件存在。
  10. - Python官方提供了`csv`模块用于操作CSV文件。
  11. <a name="by4bX"></a>
  12. #### 3.1.2 CSV基本写入
  13. - 前置知识:CSV格式的文件后缀为`.csv`
  14. - `csv.writer(file)`可以获取一个文件的handle对象,这个对象中封装了对指定CSV文件的各种操作。
  15. ```python
  16. import csv
  17. with open('./student.csv', 'w', encoding='utf-8') as file:
  18. handle = csv.writer(file)
  • handle.writerow(data)可以用于写入一行数据。(data一般是一个一维序列) ```python import csv

with open(‘./student.csv’, ‘w’, encoding=’utf-8’) as file: handle = csv.writer(file) handle.writerow([‘学号’, ‘姓名’, ‘成绩’])

  1. - student.csv文件的内容:
  2. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/2692415/1665293558422-b7dd4a21-4e6d-498b-87b9-5d40080ddd8a.png#averageHue=%23f8f7f4&clientId=u5c23e431-bac3-4&from=paste&height=86&id=u27c106a7&originHeight=107&originWidth=311&originalType=binary&ratio=1&rotation=0&showTitle=false&size=4007&status=done&style=none&taskId=udf2e0658-c997-4bb0-b99c-412d30d152b&title=&width=250)
  3. - `handle.writerows(data)`可以用于写入一行数据。(data一般是一个二维序列)
  4. ```python
  5. import csv
  6. with open('./student.csv', 'w', encoding='utf-8') as file:
  7. handle = csv.writer(file)
  8. handle.writerow(['学号', '姓名', '成绩'])
  9. handle.writerows([
  10. [10001, '乐乐', 80],
  11. [10002, '欢欢', 86],
  12. [10003, '莱莱', 75]
  13. ])
  • student.csv文件的内容:

image.png

  • 可以发现,写入多行数据时每两行数据之间会有一行多余的空行,这是由以下两个原因造成的:
    1. 因为open()中有一个newline参数,在操作文件时若没有手动指定这个参数,那么它默认就是\n
    2. csv模块在写入数据是自带一个\n
  • 解决方式:
    • 这两个原因结合在一起,就会导致一个写入操作完成时,会先进行两次换行,再写入新的数据。
    • 因此只需要干掉两个\n中的其中一个,就不会再有空行了。(一般来说将open()中的newline参数指定为空即可) ```python import csv

with open(‘./student.csv’, ‘w’, encoding=’utf-8’, newline=’’) as file: handle = csv.writer(file) handle.writerow([‘学号’, ‘姓名’, ‘成绩’]) handle.writerows([ [10001, ‘乐乐’, 80], [10002, ‘欢欢’, 86], [10003, ‘莱莱’, 75] ])

  1. - student.csv文件的内容:
  2. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/2692415/1665294679662-87d70db8-41f3-43a8-99f5-cd601cfae0ba.png#averageHue=%23f5f3f0&clientId=u5c23e431-bac3-4&from=paste&height=135&id=u6a61920b&originHeight=150&originWidth=277&originalType=binary&ratio=1&rotation=0&showTitle=false&size=7656&status=done&style=none&taskId=ua517be11-dff6-4428-b002-7fdb381b144&title=&width=250)
  3. <a name="m5E3l"></a>
  4. #### 3.1.3 CSV分隔符设置
  5. - 3.1.2中介绍的所有效果中,一行中不同的数据之间使用逗号`,`分割的,这是因为CSV文件默认的分隔符就是逗号。
  6. - 可以通过在`writer()`获取handle时指定delimiter参数的值来指定CSV文件的分割符。
  7. - 示例:将student.csv文件的分隔符设置为分号`;`
  8. ```python
  9. import csv
  10. with open('./student.csv', 'w', encoding='utf-8', newline='') as file:
  11. handle = csv.writer(file, delimiter=';')
  12. handle.writerow(['学号', '姓名', '成绩'])
  13. handle.writerows([
  14. [10001, '乐乐', 80],
  15. [10002, '欢欢', 86],
  16. [10003, '莱莱', 75]
  17. ])
  • student.csv文件的内容:

image.png

3.1.4 以字典形式写入数据

  • 字典类型的handle需要通过csv.DictWriter()函数获取,需要指定两个参数:
    • f:写入的CSV文件路径。
    • fieldnames:字典数据的键。 ```python import csv

with open(‘./student.csv’, ‘w’, encoding=’utf-8’, newline=’’) as file: dict_handle = csv.DictWriter( f=file, fieldnames=[‘学号’, ‘姓名’, ‘年龄’] )

  1. - `handle.writeheader()`可以写入CSV表的表头数据。对于字典形式写入而言,实际上就是将`DictWriter()`函数中设置的fieldnames参数值写入CSV文件。
  2. ```python
  3. import csv
  4. with open('./student.csv', 'w', encoding='utf-8', newline='') as file:
  5. dict_handle = csv.DictWriter(f=file, fieldnames=['学号', '姓名', '年龄'])
  6. dict_handle.writeheader()
  • student.csv文件的内容:

image.png

  • 两个写入函数:
    • handle.writerow(data)可以写入一行数据。(data在这里是一个字典数据)
    • handle.writerows(data)可以写入多行数据。(data在这里是一个由多个字典组成的序列)
  • 示例: ```python import csv

with open(‘./student.csv’, ‘w’, encoding=’utf-8’, newline=’’) as file: dict_handle = csv.DictWriter(f=file, fieldnames=[‘学号’, ‘姓名’, ‘年龄’]) dict_handle.writeheader()

  1. # 写入一行数据(单个字典)
  2. dict_handle.writerow({'学号': 10001, '姓名': '欢欢', '年龄': 20})
  3. # 写入多行数据(字典序列)
  4. dict_handle.writerows([
  5. {'学号': 10002, '姓名': '开开', '年龄': 23},
  6. {'学号': 10003, '姓名': '乐乐', '年龄': 18},
  7. {'学号': 10004, '姓名': '涛涛', '年龄': 25},
  8. {'学号': 10005, '姓名': '美美', '年龄': 19},
  9. ])
  1. - student.csv文件的内容:
  2. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/2692415/1665297252183-39ea2e07-36ae-4555-b63c-3302a5e0ad88.png#averageHue=%23f3f0ec&clientId=u5c23e431-bac3-4&from=paste&height=201&id=ue07048f2&originHeight=183&originWidth=228&originalType=binary&ratio=1&rotation=0&showTitle=false&size=9288&status=done&style=none&taskId=uf17e38b1-5687-44bb-8aef-7b4d60a2dfb&title=&width=250)
  3. <a name="wax4j"></a>
  4. #### 3.1.5 CSV文件数据读取
  5. - CSV文件读取思路:
  6. - 使用`open()`建立程序与CSV文件的联系。
  7. - 使用`csv.reader(file)`获取一个迭代器,文件file中的数据就是按行封装成一个列表,存储在这个迭代器中的。
  8. - 遍历这个迭代器,获取每一行数据。
  9. - 示例:读取student.csv文件中的数据。
  10. ```python
  11. import csv
  12. with open('./student.csv', 'r', encoding='utf-8') as file:
  13. # delimiter参数指定的是行中列的分隔符,缺省为逗号","
  14. # 分隔符使用缺省值可以不指定delimiter参数,但是若分隔符是其他符号则必须要指定delimiter参数
  15. reader = csv.reader(file, delimiter=",")
  16. # 遍历得到数据
  17. for data in reader:
  18. print(data, type(data))
  19. """
  20. 运行结果:
  21. ['学号', '姓名', '年龄'] <class 'list'>
  22. ['10001', '欢欢', '20'] <class 'list'>
  23. ['10002', '开开', '23'] <class 'list'>
  24. ['10003', '乐乐', '18'] <class 'list'>
  25. ['10004', '涛涛', '25'] <class 'list'>
  26. ['10005', '美美', '19'] <class 'list'>
  27. """
  • 使用csv.DictReader(file)可以获取到一个字典类型的迭代器。
    • 这个迭代器会将文件中的第一行数据解析为键,同一列的数据解析为键对应的值,然后封装成一个字典。
    • 这种类型的迭代器更方便进行数据处理,因此推荐使用DictReader()读取数据。 ```python import csv

with open(‘./student.csv’, ‘r’, encoding=’utf-8’) as file: reader = csv.DictReader(file) for data in reader: print(data, type(data))

“”” 运行结果: {‘学号’: ‘10001’, ‘姓名’: ‘欢欢’, ‘年龄’: ‘20’} {‘学号’: ‘10002’, ‘姓名’: ‘开开’, ‘年龄’: ‘23’} {‘学号’: ‘10003’, ‘姓名’: ‘乐乐’, ‘年龄’: ‘18’} {‘学号’: ‘10004’, ‘姓名’: ‘涛涛’, ‘年龄’: ‘25’} {‘学号’: ‘10005’, ‘姓名’: ‘美美’, ‘年龄’: ‘19’} “””

  1. <a name="sH4zk"></a>
  2. ### 3.2 Excel的认识与工作簿操作
  3. <a name="s7lv1"></a>
  4. #### 3.2.1 Excel介绍
  5. - Excel是微软开发的一款电子表格办公软件,用二维表(数据采用行和列的形式组织)的形式组织数据。
  6. - Excel文件结构:
  7. - 一个Excel文件(后缀为".xlsx"的文件)被称为一个工作簿;
  8. - 一个工作簿由多个Sheet(工作单元表)组成;
  9. - 一个Sheet中有多个行与多个列;
  10. - 一个确定的行与一个确定的列组合确定了一个Cell(单元格)。
  11. - Excel是数据分析中常用的一款数据工具,因此学习如何用Python程序与Excel交互是一项十分重要的技能。
  12. - Python没有提供直接操作Excel的工具,因此需要安装第三库openpyxl。
  13. ```python
  14. pip install openpyxl

3.2.2 工作簿的创建

  • 工作簿(Excel)创建流程:
    • 导入openpyxl模块。
    • 调用openpyxl模块中的Workbook()函数创建一个工作簿对象。
    • 调用工作簿对象的save(file_path)保存为一个实际的Excel文件,其中file_path表示生成的Excel文件完整的路径名。
      • 注意:当file_path对应的Excel文件已经被打开时,save()函数执行会报错。
  • 代码实现:在当前目录的excel目录中创建一个名为学生表.xlsx和名为家长表.xlsx的Excel文件。 ```python import openpyxl

创建学生表.xlsx

student_workbook = openpyxl.Workbook() # 创建工作簿对象 student_workbook.save(“./excel/学生表.xlsx”) #命名保存

创建家长表.xlsx

parent_workbook = openpyxl.Workbook() # 创建工作簿对象 parent_workbook.save(“./excel/家长表.xlsx”) #命名保存

  1. - 运行完成后,在excel目录中会出现学生版.xlsx和家长表.xlsx文件,这两个文件中都带有一个默认的单元表Sheet
  2. <a name="fgk3f"></a>
  3. #### 3.2.3 工作簿的删除
  4. - 工作簿本质上还是计算机中的一个文件,要删除一个工作簿与删除一个普通的计算机文件没有任何区别。
  5. - 示例:删除家长表.xlsx文件。
  6. ```python
  7. import os
  8. os.remove("./excel/家长表.xlsx")

3.2.4 读入已存在的工作簿

  • 采用openpyxl模块中的load_workbook(file_pach)函数可以读入指定路径下已存在的工作簿。 ```python import openpyxl

workbook = openpyxl.load_workbook(“./excel/学生表.xlsx”) print(workbook) #

  1. - 注意,后续对单元表、单元格的各种操作,都是针对工作簿对象workbook的,且workbook即可以是创建出来的,也可以是导入进来的,操作上没有任何区别。
  2. <a name="pBtHg"></a>
  3. ### 3.3 单元表的相关操作
  4. <a name="guTtt"></a>
  5. #### 3.3.1 当前工作簿中所有单元表
  6. - 采用`工作簿对象.sheetnames`可以获取到当前工作簿中所有的单元表的表名构成的列表。
  7. - 一般情况下,初始只有一个单元表Sheet
  8. ```python
  9. import openpyxl
  10. student_workbook = openpyxl.load_workbook("./excel/学生表.xlsx")
  11. sheet_names = student_workbook.sheetnames
  12. print(sheet_names) # ['Sheet']
  • 采用工作簿对象.worksheets可以获取到当前工作簿中所有的单元表对象构成的列表。 ```python import openpyxl

student_workbook = openpyxl.load_workbook(“./excel/学生表.xlsx”)

worksheet_list = student_workbook.worksheets print(worksheet_list) # []

  1. <a name="oAkTo"></a>
  2. #### 3.3.2 定位单元表
  3. - 根据索引获取单元表:通过索引`工作簿对象.worksheets`中的元素可以获取指定的单元表对象。
  4. ```python
  5. import openpyxl
  6. student_workbook = openpyxl.load_workbook("./excel/学生表.xlsx")
  7. worksheet_0 = student_workbook.worksheets[0]
  8. print(worksheet_0) # <Worksheet "Sheet">
  • 根据单元表名获取单元表:使用工作簿对象[单元表表名]的方式可以获取到指定名称的单元表对象。 ```python import openpyxl

student_workbook = openpyxl.load_workbook(“./excel/学生表.xlsx”)

worksheet_0 = student_workbook[“Sheet”] print(worksheet_0) #

  1. <a name="Pf4DY"></a>
  2. #### 3.3.3 修改单元表表名
  3. - 采用`单元表对象.title = 单元表名`的方式可以修改指定单元表的表名。
  4. - 注意:对工作簿中任何内容做出任何修改时,都要调用`工作簿对象.save(file_path)`函数进行保存;否则修改不生效。
  5. ```python
  6. import openpyxl
  7. student_workbook = openpyxl.load_workbook("./excel/学生表.xlsx")
  8. worksheet_0 = student_workbook["Sheet"]
  9. worksheet_0.title = "学生名单"
  10. print(worksheet_0) # <Worksheet "学生名单">
  11. student_workbook.save("./excel/学生表.xlsx")
  • 此时打开”./excel/学生表.xlsx”对应的文件,会发现学生表.xlsx底部的Sheet单元表消失了,取而代之的是“学生名单”。

    3.3.4 新建单元表

  • 采用单元表对象变量 = 工作簿对象.create_sheet("单元表表名", 索引)的方式创建新的单元表,并且会返回对应的单元表对象。

    • 索引就是sheetnames列表中的索引,从0开始(Sheet就是默认索引为0的单元表)。 ```python import openpyxl

student_workbook = openpyxl.load_workbook(“./excel/学生表.xlsx”)

score_table = student_workbook.create_sheet(“考试成绩”, 1) contact_inf = student_workbook.create_sheet(“学生家庭联系方式”, 2) print(student_workbook.worksheets) # [, , ]

student_workbook.save(“./excel/学生表.xlsx”)

  1. - 此时打开"./excel/学生表.xlsx"对应的文件,会发现学生表.xlsx底部多了考试成绩表和学生家庭联系方式表两张单元表。
  2. - 修改工作簿的操作不会影响未操作的数据,因此学生名单单元表依旧存在,且及其中的数据不会发生任何改变(若有数据的话)。
  3. <a name="penUB"></a>
  4. #### 3.3.5 删除单元表
  5. - 采用`工作簿对象.remove(单元表对象)`的方式删除指定的单元表。
  6. ```python
  7. import openpyxl
  8. student_workbook = openpyxl.load_workbook("./excel/学生表.xlsx")
  9. print(student_workbook.sheetnames) # ['学生名单', '考试成绩', '学生家庭联系方式']
  10. # 删除考试成绩表和学生家庭联系方式表
  11. score_table = student_workbook["考试成绩"]
  12. student_workbook.remove(score_table)
  13. contact_inf = student_workbook["学生家庭联系方式"]
  14. student_workbook.remove(contact_inf)
  15. print(student_workbook.sheetnames) # ['学生名单']
  16. student_workbook.save("./excel/学生表.xlsx")
  • 此时打开”./excel/学生表.xlsx”对应的文件,会发现学生表.xlsx底部只有学生名单表了,考试成绩表和学生家庭联系方式表被删除了。

    3.4 单元格数据插入

    3.4.1 插入一个Cell的数据

  • Cell(单元格)插入数据流程:

    • 获取单元表。
    • 在单元表的指定单元格内插入数据,有以下两种方式。
      • 单元格的行索引和列索引都是从1开始依次递增的,故可以用单元表对象.cell(行索引, 列索引, 数据)的方式插入数据。
      • 列除了用数字索引外,还可以用A、B、C这样的方式表示,故可以用单元表对象["B1"] = 数据的方式插入数据。
  • 实例:在学生名单单元表中,用第一种方式在第1行第1列中插入字符串数据“学号”,然后用第二种方式在下面两行插入两个学号。 ```python import openpyxl

定位工作簿和单元表

student_workbook = openpyxl.load_workbook(“./excel/学生表.xlsx”) student_list = student_workbook[“学生名单”]

插入数据

student_list.cell(1, 1, “学号”) student_list[“A2”] = 1001 student_list[“A3”] = 1002

保存修改

student_workbook.save(“./excel/学生表.xlsx”)

  1. <a name="hMsst"></a>
  2. #### 3.4.2 修改单元格中的数据
  3. - 修改单元格的数据实际上就是再向指定的单元格内插入一次数据,依旧调用cell()函数。
  4. - 示例:将A2单元格中的数据改为1003
  5. ```python
  6. import openpyxl
  7. # 定位工作簿和单元表
  8. student_workbook = openpyxl.load_workbook("./excel/学生表.xlsx")
  9. student_list = student_workbook["学生名单"]
  10. # 修改单元格的数据
  11. student_list["A2"] = 1003
  12. # 保存修改
  13. student_workbook.save("./excel/学生表.xlsx")

3.4.3 插入一整行数据

  • 实现思路:
    • 可以将一整行中的所有数据封装成一个列表。
    • 然后遍历这个列表的enumerate()对象,可以获取到列表中的所有数据以及其对应的索引。
    • 用cell()函数插入数据,一般来说一整行数据的行是固定的,每个数据的列也和其索引位置有着直接的关系。
  • 代码实现:在Excel的第一行添加数据标题即:学号、姓名、年龄、性别、班级,然后在第二行插入一行数据:1001、Dosbo、20、男、软件工程2022。 ```python import openpyxl

定位工作簿和单元表

student_workbook = openpyxl.load_workbook(“./excel/学生表.xlsx”) student_list = student_workbook[“学生名单”]

插入数据

titles = [“学号”, “姓名”, “年龄”, “性别”, “班级”] for position, title in enumerate(titles): student_list.cell(1, position + 1, title) # 行固定为1,列为索引值加一。

datas = [1001, “Dosbo”, 20, “男”, “软件工程2022”] for position, data in enumerate(datas): student_list.cell(2, position + 1, data) # 行固定为2,列为索引值加一。

保存修改

student_workbook.save(“./excel/学生表.xlsx”)

  1. <a name="h4ojm"></a>
  2. #### 3.4.4 插入多行数据
  3. - 实现思路:
  4. - 一行数据采用一个一维列表封装,那么多行数据固然采用二维列表进行封装(表头标题也可以封装进来)。
  5. - 首先遍历外层的enumerate(),会得到内层列表的索引值以及一整行数据。
  6. - 接着再遍历内层的enumerate(),就可以获取具体的数据值以及其在内层列表中的索引。
  7. - 外层列表的索引往往对应着行,内层列表的索引则往往对应着列。既然行、列、数据都拿到了,那么直接用cell()函数插入数据即可。
  8. - 实例:向Excel中插入如下数据:
  9. ![__](G`S`E)}2SZXH5IJ]K@Q.png](https://cdn.nlark.com/yuque/0/2022/png/2692415/1665469123385-ab134c7e-9b2b-475d-88be-ee0f07d8238e.png#averageHue=%23d7d7d7&clientId=ucb1218c4-c699-4&from=paste&height=86&id=u2c236bab&originHeight=91&originWidth=637&originalType=binary&ratio=1&rotation=0&showTitle=false&size=7275&status=done&style=none&taskId=uc999bbf5-caa3-4f3c-8233-811616a626d&title=&width=600)
  10. - 代码实现:
  11. ```python
  12. import openpyxl
  13. # 定位工作簿和单元表
  14. student_workbook = openpyxl.load_workbook("./excel/学生表.xlsx")
  15. student_list = student_workbook["学生名单"]
  16. # 封装数据
  17. datas = [
  18. ["学号", "姓名", "年龄", "性别", "班级", "计算机科学导论", "软件工程导论", "大数据导论"],
  19. [1001, "Dosbo", 20, "男", "软件工程2022", 89, 72, 61],
  20. [1002, "Adam", 21, "男", "计科2022", 82, 89, 51],
  21. [1003, "Mark", 23, "男", "软件工程2019", 91, 75, 60],
  22. [1004, "Mary", 20, "女", "大数据2022", 95, 82, 71]
  23. ]
  24. # 插入数据
  25. for line, line_data in enumerate(datas):
  26. for column, data in enumerate(line_data):
  27. student_list.cell(line + 1, column + 1, data)
  28. # 保存修改
  29. student_workbook.save("./excel/学生表.xlsx")

3.4.5 插入公式数据

  • 目标效果:

image.png

  • 实现思路:
    • 以表中I2单元格为例,其公式为:=SUM(F2:H2)
    • 因此可以推断出,I2~I5单元格的公式为=SUM(F{line}:H{line})
    • 因此只需要定位到目标单元格,然后将公式写进去即可。
  • 实现思路:(这里仅仅插入I列,A~H列的基本数据写入在3.4.4中已经实现) ```python import openpyxl

student_workbook = openpyxl.load_workbook(“./excel/学生表.xlsx”) student_list = student_workbook[“学生名单”]

写入标题

student_list[“I1”] = “总成绩”

写入公式数据

for line in range(2, 6): student_list[f”I{line}”] = f”=SUM(F{line}:H{line})”

student_workbook.save(“./excel/学生表.xlsx”)

  1. <a name="BXogA"></a>
  2. ### 3.5 单元表样式设计
  3. <a name="U44Is"></a>
  4. #### 3.5.1 行高与列宽设置
  5. - `单元表对象.row_dimensions[line].height = h`可以将单元表中第line行的行高设置为h。
  6. - `单元表对象.column_dimensions[col].width = w`可以将单元表中第col列的列宽设置为w。
  7. - 示例:将学生表.xlsx文件中的学生名单表的第3行的行高设置为30,第B列的列宽设置为20。
  8. ```python
  9. import openpyxl
  10. student_workbook = openpyxl.load_workbook("./excel/学生表.xlsx")
  11. student_list = student_workbook["学生名单"]
  12. student_list.row_dimensions[3].height = 30
  13. student_list.column_dimensions['B'].width = 20
  14. student_workbook.save("./excel/学生表.xlsx")

3.5.2 字体设置

  • 单元格字体的设置思路:
    • 字体首先要构造openpyxl.styles.Font对象,这个对象常用的构造参数有:
      • name:字体名称
      • size(或sz):字号大小
      • bold(或b):是否加粗
      • italic(或i):是否斜体
      • charset:编码集
      • color:颜色(一般用的十六进制颜色数据)
    • 接着就是要定位单元格,依旧使用cell()函数,只不过此时只需要指定单元格的行标和列表,不需要设置内容。
    • 最后,只要将单元格的font属性指定为构造的Font对象即可。
  • 示例:将第4行第3列的单元格设置为楷体、18号字、颜色为ad4e2f、加粗、斜体。 ```python import openpyxl from openpyxl.styles import Font

student_workbook = openpyxl.load_workbook(“./excel/学生表.xlsx”) student_list = student_workbook[“学生名单”]

设置字体

student_list.cell(4, 3).font = Font(name=”楷体”, size=18, color=”ad4e2f”, bold=True, italic=True)

student_workbook.save(“./excel/学生表.xlsx”)

  1. <a name="uOoNZ"></a>
  2. #### 3.5.3 对其模式设置
  3. - 单元格对其模式的设置思路:
  4. - 对其模式首先要构造`openpyxl.styles.Alignment`对象,这个对象常用的构造参数有:
  5. - horizontal:横向对其模式,常用的值有:left左对齐、center居中对齐、right右对齐。
  6. - vertical:纵向对其模式,常用的值有:top顶部对齐、center居中对齐、bottom底部对齐。
  7. - 接着就是使用`cell()`函数定位单元格。
  8. - 最后,将单元格的`alignment`属性指定为构造的`Alignment`对象即可。
  9. - 示例:将第4行第3列的单元格设置为横向居中对齐,纵向顶部对齐。
  10. ```python
  11. import openpyxl
  12. from openpyxl.styles import Alignment
  13. student_workbook = openpyxl.load_workbook("./excel/学生表.xlsx")
  14. student_list = student_workbook["学生名单"]
  15. # 设置对其模式
  16. student_list.cell(4, 3).alignment = Alignment(horizontal="center", vertical="top")
  17. student_workbook.save("./excel/学生表.xlsx")

3.5.4 边框设置

  • 设置边框首先要设置边对象(openpyxl.styles.Side对象),Side对象有以下两个属性:

    • style:边样式,其值包括:

      1. style = NoneSet(values=('dashDot','dashDotDot', 'dashed','dotted',
      2. 'double','hair', 'medium', 'mediumDashDot', 'mediumDashDotDot',
      3. 'mediumDashed', 'slantDashDot', 'thick', 'thin')
      4. )
    • color:边颜色,一般用的十六进制颜色数据。

  • 示例:构造一条样式为mediumDashDot的黑边。 ```python from openpyxl.styles import Border, Side

side = Side(style=’mediumDashDot’, color=’000000’)

  1. - 单元格边框设置思路:
  2. - 对其模式首先要构造`openpyxl.styles.Border`对象,这个对象有以下四个基本属性:
  3. - left:边框左边。
  4. - right:边框右边。
  5. - top:边框底边。
  6. - bottom:边框顶边。
  7. - 这四个边参数都可以指定为`openpyxl.styles.Side`的对象。
  8. - 接着就是使用`cell()`函数定位单元格,并将其`border`属性指定为构造的`Border`对象即可。
  9. - 示例:为第4行第3列的单元格设置边框,样式为:顶边与底边为dashDotDot的红边,左边与右边为mediumDashDot的黑边。
  10. ```python
  11. import openpyxl
  12. from openpyxl.styles import Border, Side
  13. student_workbook = openpyxl.load_workbook("./excel/学生表.xlsx")
  14. student_list = student_workbook["学生名单"]
  15. # 定义边
  16. red_side = Side(style='dashDotDot', color='ff0000')
  17. black_side = Side(style='mediumDashDot', color='000000')
  18. # 设置边框
  19. student_list.cell(4, 3).border = Border(
  20. top=red_side, bottom=red_side,
  21. left=black_side, right=black_side
  22. )
  23. student_workbook.save("./excel/学生表.xlsx")

3.6 数据查询

3.6.1 读取指定单元格的数据

  • 查询指定单元格的数据很简单,只需要先定位到具体的单元格对象,然后调用单元格对象.value属性即可。 ```python import openpyxl

定位工作簿和单元表

student_workbook = openpyxl.load_workbook(“./excel/学生表.xlsx”) student_list = student_workbook[“学生名单”]

定位单元格并查询数据

cell_d4 = student_list[“D4”] print(cell_d4.value) # 男

cell_2_2 = student_list.cell(2, 2) print(cell_2_2.value) # Dosbo

  1. <a name="crRyt"></a>
  2. #### 3.6.2 查询单元表中数据的规模
  3. - 调用`单元表对象.max_row`可以获取单元表中数据的总行数(数据间的空行也算)。
  4. - 调用`单元表对象.max_column`可以获取单元表中数据的总列数(数据间的空行也算)。
  5. ```python
  6. import openpyxl
  7. # 定位工作簿和单元表
  8. student_workbook = openpyxl.load_workbook("./excel/学生表.xlsx")
  9. student_list = student_workbook["学生名单"]
  10. # 定位单元表的数据规模
  11. print(f"学生名单表的数据总行数为:{student_list.max_row}") # 学生名单表的数据总行数为:5
  12. print(f"学生名单表的数据总列数为:{student_list.max_column}") # 学生名单表的数据总列数为:9

3.6.3 按行查询工作簿中的数据

  • 实现思路:

    • 采用单元表对象.rows可以以行为单位获取到工作簿中的所有数据。

      • 每一行数据被封装成一个元组。
      • 元组中的每个元组都是一个Cell对象,格式为:<Cell 单元表表名.单元格位置>
        1. (<Cell '学生名单'.A1>, <Cell '学生名单'.B1>, <Cell '学生名单'.C1>, <Cell '学生名单'.D1>, <Cell '学生名单'.E1>)
    • 遍历行元组中的每一个Cell,再调用Cell对象中的value属性,就可以获取到单元格的实际数据。

  • 代码实现:按行查询学生表.xlsx文件中学生名单表中的数据。 ```python import openpyxl

定位工作簿和单元表

student_workbook = openpyxl.load_workbook(“./excel/学生表.xlsx”) student_list = student_workbook[“学生名单”]

按行查询数据

for row_data in student_list.rows: for cell in row_data: print(cell.value, end=’\t’) print()

  1. - 运行结果:
  2. ```python
  3. 学号 姓名 年龄 性别 班级 计算机科学导论 软件工程导论 大数据导论 总成绩
  4. 1001 Dosbo 20 男 软件工程2022 89 72 61 =SUM(F2:H2)
  5. 1002 Adam 21 男 计科2022 82 89 51 =SUM(F3:H3)
  6. 1003 Mark 23 男 软件工程2019 91 75 60 =SUM(F4:H4)
  7. 1004 Mary 20 女 大数据2022 95 82 71 =SUM(F5:H5)

3.6.4 按列查询工作簿中的数据

  • 实现思路:采用单元表对象.columns可以以列为单位获取到工作簿中的所有数据,其他与按行查询一样。

    1. (<Cell '学生名单'.A1>, <Cell '学生名单'.A2>, <Cell '学生名单'.A3>, <Cell '学生名单'.A4>, <Cell '学生名单'.A5>)
  • 代码实现:按列查询学生表.xlsx文件中学生名单表中的数据。 ```python import openpyxl

定位工作簿和单元表

student_workbook = openpyxl.load_workbook(“./excel/学生表.xlsx”) student_list = student_workbook[“学生名单”]

按列查询数据

for column_data in student_list.columns: for cell in column_data: print(cell.value, end=’\t’) print()

  1. - 运行结果:
  2. ```python
  3. 学号 1001 1002 1003 1004
  4. 姓名 Dosbo Adam Mark Mary
  5. 年龄 20 21 23 20
  6. 性别 男 男 男 女
  7. 班级 软件工程2022 计科2022 软件工程2019 大数据2022
  8. 计算机科学导论 89 82 91 95
  9. 软件工程导论 72 89 75 82
  10. 大数据导论 61 51 60 71
  11. 总成绩 =SUM(F2:H2) =SUM(F3:H3) =SUM(F4:H4) =SUM(F5:H5)

3.6.5 读取公式单元格的数据

  • 不管在3.6.3还是3.6.4中,读取到I列总成绩时,显示都是单元格中的公式,而不是公式计算得到的结果。

1665631068179.jpg

  • 读取实际数据的操作:
    • 打开需要读取的目标Excel文件,然后按Ctrl + S保存。(必须做,是一个BUG)
    • 然后将load_workbook()函数中的data_only参数值设置为True。
    • 接着即可正常读取出公式计算得到的值了。
  • 代码实现: ```python

    运行前先打开Excel,然后按Ctrl + S保存一次再关闭。

    import openpyxl

定位工作簿和单元表

student_workbook = openpyxl.load_workbook(“./excel/学生表.xlsx”, data_only=True) student_list = student_workbook[“学生名单”]

按行查询数据

for row_data in student_list.rows: for cell in row_data: print(cell.value, end=’\t’) print()

  1. - 运行结果:
  2. ```python
  3. 学号 姓名 年龄 性别 班级 计算机科学导论 软件工程导论 大数据导论 总成绩
  4. 1001 Dosbo 20 男 软件工程2022 89 72 61 222
  5. 1002 Adam 21 男 计科2022 82 89 51 222
  6. 1003 Mark 23 男 软件工程2019 91 75 60 226
  7. 1004 Mary 20 女 大数据2022 95 82 71 248

3.6.6 读取指定列的数据

  • 通过类似于单元表对象["A1:A5"]的形式可以获取到一列数据,这个数据是一个由多个单元组构成的元组。

    1. ((<Cell '学生名单'.A1>,), (<Cell '学生名单'.A2>,), (<Cell '学生名单'.A3>,), (<Cell '学生名单'.A4>,), (<Cell '学生名单'.A5>,))
  • 处理思路:

    • 遍历外层元组中所有的内层单元组。
    • 然后获取每个单元组中0索引位上的元素即可得到这列上的每个Cell对象。
    • 再调用value就可得到值。 ```python import openpyxl

定位工作簿和单元表

student_workbook = openpyxl.load_workbook(“./excel/学生表.xlsx”) student_list = student_workbook[“学生名单”]

读取指定列的数据

for tup_cell in student_list[“A1:A5”]: print(tup_cell[0].value)

  1. <a name="tSxeS"></a>
  2. #### 3.6.7 读取指定行的数据
  3. - 通过类似于`单元表对象["A1:E1"]`的形式可以获取到一行数据,这个数据是一个单元组。
  4. - 这个单元组中的唯一的一个元素就是这一行中所有Cell对象构成的元组。
  5. ```python
  6. ((<Cell '学生名单'.A1>, <Cell '学生名单'.B1>, <Cell '学生名单'.C1>, <Cell '学生名单'.D1>, <Cell '学生名单'.E1>),)
  • 处理思路:
    • 先获取外层元组0索引位的元素,即这一行中所有Cell构成的元组。
    • 遍历这个元组中所有的Cell,并调用每个Cell的value就可得到值。 ```python import openpyxl

定位工作簿和单元表

student_workbook = openpyxl.load_workbook(“./excel/学生表.xlsx”) student_list = student_workbook[“学生名单”]

读取指定列的数据

for cell in student_list[“A1:E1”][0]: print(cell.value, end=”\t”)

  1. <a name="MLEJ2"></a>
  2. #### 3.6.8 读取指定范围的数据
  3. - 通过类似于`单元表对象["A1:E5"]`的形式可以获取到一个连续的范围内的数据。
  4. - 这个数据是一个由多个行元组构成的元组,数据格式与处理方式都与2.5.3类似。
  5. ```python
  6. import openpyxl
  7. # 定位工作簿和单元表
  8. student_workbook = openpyxl.load_workbook("./excel/学生表.xlsx")
  9. student_list = student_workbook["学生名单"]
  10. # 读取指定范围的数据
  11. for row_data in student_list["A1:E5"]:
  12. for cell in row_data:
  13. print(cell.value, end="\t")
  14. print()