第5章
文 件 读 写



第5章文件读写
文件是计算机存储数据的重要形式,用文件组织和表达数据更加有效和灵活。文件有不同的编码和存储形式,如文本文件、图像文件、音频和视频文件、数据库文件、特定格式文件等。每个文件都有各自的文件名和属性,对文件进行操作是Python的重要功能。
5.1TXT文件读写
5.1.1读取文件全部内容

文本文件的读写通常有3个基本步骤: 打开文件、读写文件和关闭文件。
1. 文件打开模式
对文件访问之前,必须先打开文件,并指定被打开的文件做什么操作。在Python中,通过标准内置函数open()打开一个文件并获得一个文件对象。语法格式如下。



1

2
文件句柄=open('文件路径和名称', '操作模式')

with open('文件路径和名称', '操作模式') as 文件句柄:
# 文件打开语法1

# 文件打开语法2

(1) 文件读写是一个非常复杂的过程,它涉及设备(如硬盘)、通道(数据传输方式)、路径(文件存放位置)、进程(读写操作)、文件缓存(文件在内存中的存放)等复杂问题。文件句柄是简化文件读写的变量,它隐藏了设备、通道、路径、进程、缓存等复杂操作,帮助程序员关注正在处理的文件。文件句柄用变量名表示,通过open()函数把它和文件连接,文件读写完成后,关闭文件就会释放文件句柄占用的资源。
(2) 文件打开或创建成功后,文件句柄就代表了打开的文件对象,这简化了程序语句。我们可以得到这个文件的各种信息(属性)。
(3) 文件可以采用相对路径,如"江南春.txt"; 也可以采用绝对路径(包含完整目录的文件名),如"d:\\test\\05\\江南春.txt"。路径前面有r参数是保持路径中字符串原始值的意思,也就是说不对其中的符号进行转义。路径采用\表示时,可以加上r参数,如r"d:\test\05\江南春.txt"。注意,路径采用\\表示时,不要加r参数。
(4) 文件读取时,会同时读取行末尾包含的回车换行符号(\n)。
(5) 操作模式用于控制文件打开方式,文件打开的操作模式及参数说明如表51所示。


表51文件打开的操作模式及参数说明



操 作 模 式参 数 说 明
r仅读,待打开的文件必须存在; 文件不存在时会返回异常FileNotFoundError
w
仅写,若文件已存在,内容将先被清空; 若文件不存在则创建文件,不可读
续表


操 作 模 式参 数 说 明
a
仅写,若文件已存在,则在文件最后追加新内容; 若文件不存在则创建文件
r+
可读,可写,可追加; 待打开的文件必须存在(“+”参数说明允许读和写)
a+
读写,若文件已存在,则内容不会被清空
w+
读写,若文件已存在,则内容将先被清空

rb
仅读,读二进制文件; 待打开的文件必须存在(“b”参数说明读写二进制文件)
wb
仅写,写二进制文件; 若文件已存在,则内容将先被清空
ab
仅写,写二进制文件; 若文件已存在,则内容不会被清空

【例51】打开当前目录下test.txt文件,对它进行覆盖写操作。



f = open("test.txt", "w")# 以写模式打开文件,f=文件句柄,相对路径

2. 关闭文件
文件使用结束后一定要关闭,这样才能保存文件内容,释放文件占用内存。



文件句柄.close()# 文件关闭的语法格式

3. 文件读取函数
Python提供了read()、readlines()和readline()三个文件读取函数。这三种函数都会把文件每行末尾的'\n'(换行符)也读进来,可以用splitlines()等函数删除换行符。



(1) read()函数一次读取文件的全部内容,返回值存放在一个大字符串中。它的优点是方便、简单、速度最快; 它的缺点是文件过大时,占用内存很大。
【例52】用read()函数读取“琴诗.txt”文件中全部内容。



1

2

3

>>>f = open("d:\\test\\05\\琴诗.txt", "r")

>>>s = f.read( )

>>>s

'[宋] 苏轼《琴诗》\n若言琴上有琴声,放在匣中何不鸣?\n若言声在指头上,何不于君指上听?\n'# 打开文件,f为文件句柄

# 读文件全部内容

# 输出内容为字符串

# \n为换行符




【例53】读取“琴诗.txt”文件中全部内容,并且删除文件中的回车符。




1

2

3

4

>>>f = open("d:\\test\\05\\琴诗.txt", "r")

>>>s = f.read( )

>>>s = s.splitlines()

>>>s

['[宋] 苏轼《琴诗》', '若言琴上有琴声,放在匣中何不鸣?', '若言声在指头上,何不于君指上听?']
# 打开文件,f为文件句柄

# 读文件全部内容

# 删除字符串中的换行符

# 输出内容已转换为列表

# 输出已经删除换行符


(2)  readlines()函数一次读取全部文件,它自动将文件内容分解成一个大的列表,该列表可以用for循环进行处理。它的缺点是读取大文件时会比较占内存。
【例54】用readlines()函数读取“琴诗.txt”文件中全部内容。



1

2

>>>f = open("d:\\test\\05\\琴诗.txt", "r")

>>>f.readlines( )

['[宋] 苏轼《琴诗》\n', '若言琴上有琴声,放在匣中何不鸣?\n', '若言声在指头上,何不于君指上听?\n']# 打开文件,f为文件句柄

# 读文件全部内容

# 输出内容为列表


(3) readline()函数每次只读取一行,返回值是字符串。它的读取速度比readlines()慢得多,只有在没有足够内存一次读取整个文件时,才应该使用readline()函数。
【例55】用readline()函数读取“琴诗.txt”文件中一行内容。



1

2



3>>>f = open("d:\\test\\05\\琴诗.txt", "r")

>>>f.readline( )

'[宋] 苏轼《琴诗》\n'

>>>f.close( )# 打开文件,f为文件句柄

# 读文件一行内容

# 输出一行字符串

# 关闭文件



5.1.2文件遍历
文件遍历就是读取文件中每个数据,然后对遍历结果进行某种操作。如输出遍历结果; 将遍历结果赋值到某个列表; 对遍历结果进行统计(如字符数,段落数等); 对遍历结果进行排序; 将遍历结果添加到其他文件等操作。遍历是一个非常重要的操作。
1. 文件遍历方法
用open()语句或with open()语句都可以实现文件遍历,它们的差别如下。
(1) 用open()语句读取文件后,需要用close()关闭文件; 用with open()语句读取文件结束后,语句会自动关闭文件,不需要再写close()语句。
(2) 用open()语句读取文件如果发生异常,语句没有任何处理功能; 用with open()语句会处理好上下文产生的异常。
(3) 用open()语句一次只能读取一个文件; 用with open()语句一次可以读取多个文件。
【例56】文件遍历方法1: 逐行读取文件内容。



1

2

3

4
#E0506.py

with open('登鹳雀楼.txt') as file_obj:

content = file_obj.read()

print(content)
# 【文件遍历1】

# 打开文件(相对路径,当前目录在d:\test\05)

# 循环读取文件中每一行

# 输出行内容

>>>…(输出略)
# 程序运行结果

【例57】文件遍历方法2: 一次全部读入文件内容到列表,再逐行遍历列表。



1

2

3

4

5

6

7
#E0507.py

f = open('d:\\test\\05\\登鹳雀楼.txt', 'r')

L = f.readline()

while L:

print(L, end='')

L = f.readline()

f.close()
# 【文件遍历2】

# 打开文件(绝对路径)

# 将文件内容一次全部读入列表L

# 循环输出列表L中的内容

# 参数end=''为不换行输出

# 读取列表中行的内容

# 关闭文件

>>>…(输出略)
# 程序运行结果

【例58】文件遍历方法3: 循环读取文件内容到列表,再输出列表。



1

2

3
#E0508.py

for myList in open("登鹳雀楼.txt"):

print(myList)
# 【文件遍历3】

# 打开文件,循环输出列表内容(相对路径)

# 输出列表内容

>>>…(输出略)
# 程序运行结果

【例59】文件遍历方法4: 文件内容一次全部读入列表,再逐行遍历列表内容。



1

2

3

4

5

6
#E0509.py

f = open("d:\\test\\05\\登鹳雀楼.txt", "r")

L = f.readlines()

for myList in L:

print(myList, end='')

f.close()
# 【文件遍历4】

# 打开文件,前面r=路径,后面"r"=读操作

# 读取文件全部内容到列表

# 循环读取列表中的行

# 输出行内容(没有end=''参数会多输出一些空行)

# 关闭文件

>>>…(输出略)
# 程序运行结果

【例510】文件遍历方法5: 一次读取两个文件全部内容到列表,再输出列表。



1

2

3

4
#E0510.py

with open("金庸名言1.txt", 'r') as f1, open("金庸名言2.txt", 'r') as f2:

print(f1.read())

print(f2.read())
# 【文件遍历5】

# 读入两个文件

# 打印第一个文件

# 打印第两个文件

>>>

侠之大者,为国为民。

——金庸《射雕英雄传》

只要有人的地方就有恩怨,有恩怨就会有江湖,人就是江湖。

——金庸《笑傲江湖》
# 程序运行结果





2. 用if语句判断文件是否结束
【例511】用if语句判断文件是否结束。



1

2

3

4

5

6

7

8

9

10

11
#E0511.py

filename = "d:\\test\\05\\登鹳雀楼.txt"

file = open(filename, 'r')

done = 0

while not done:

Line = file.readline()

if (Line != ''):

print(Line)

else:

done = 1

file.close()
# 【判断文件是否结束】

# 路径变量赋值

# 读取文件全部内容,file为文件句柄,r为读取模式

# 初始化循环终止变量

# 循环读取文件行

# 读取文件行

# 如果Line不等于空,则文件没有结束

# 输出行内容



# 退出循环标识

# 关闭文件

>>>…(输出略)
# 程序运行结果

程序第7行,if (Line !='')为判断第6行readline()语句读到的内容是否为空,行内容为空意味着文件结束。如果readline()语句读到一个空行,也会判断为文件结束吗?事实上空行并不会返回空值,因为空行的末尾至少还有一个回车符(\n)。所以,即使文件中包含空行,读入行的内容也不为空,这说明if (Line !='')语句判断是正确的。
5.1.3读取文件指定行
1. 文件指针
文件打开后,对文件的读写有一个读取指针(元素索引号),从文件中读入内容时,读取指针不断向文件尾部移动,直到文件结束位置。Python提供了两个读写文件指针位置相关的函数tell()和seek()。它们的语法格式如下。



1

2
文件对象名.tell()

文件对象名.seek(偏移量[, 偏移位置])
# 获取当前文件操作指针的位置

# 改变当前文件操作指针的位置

参数“偏移量”表示要移动的字节数,若为正数则向文件尾部移动,若负数则向文件头部移动。
参数“偏移位置”值为0表示文件开头,值为1表示当前位置,值为2表示文件结尾。
【例512】获取文件指针位置。



1

2



3



4


>>>f = open('d:\\test\\05\\琴诗.txt')

>>>f.tell()

0

>>>f.seek(10)

10

>>>f.seek(0, 2)

85
# 打开文件

# 获得当前文件读取指针



# 将文件指针向后移动10字节



# 将文件读取指针移动到文件尾部

# 文件大小为85字节

注意,tell()方法中,size代表字节数,这里数字、英文字符、回车符(包括空行回车符)占1字节,而汉字和中文标点符号占2字节。
2. 读取文件指定行
【例513】文件“成绩utf8.txt”内容如下所示。



学号,姓名,班级,古文,诗词,平均

1,宝玉,01,70,85,0

2,黛玉,01,85,90,0

3,晴雯,02,40,65,0

4,袭人,02,20,60,0

用readlines()函数读出文件到列表,从列表对指定数据进行切片。



1

2

3

4

5

6
#E0513.py

fileName = 'd:\\test\\05\\成绩utf8.txt'

with open(fileName, 'r', encoding='UTF-8') as f:

lines = f.readlines()

for i in lines[1:3]:

print(i.strip('\n'))
# 【读文件指定行】

# 路径赋值(绝对路径)

# 打开文件(文件编码为UTF-8)

# 读取全部文件到列表lines

# 列表切片,循环读取1、2行

# 函数strip()删除字符串两端的空格

>>>

1,宝玉,01,70,85,0

2,黛玉,01,85,90,0
# 程序运行结果



程序第5行,for i in lines[1:3]语句中,[1:3]为列表切片索引号位置,其中,0行是表头不读取,列表第3行不包含,因此语句功能为循环读取列表1、2行。
程序扩展: 如果希望对文件数据隔一行读一行时,只需要修改程序第5行中列表索引号即可,如“for i in lines[1:4:2]:”,该语句表示读取列表1~4行,步长为2(即读1、3行)。
【例514】用标准模块linecache中的getline()函数读出文件指定行。



1

2

3

4
#E0514.py

import linecache

s = linecache.getline('d:\\test\\05\\成绩.txt', 1)

print('第1行:', s)     

# 【读文件指定行】

# 导入标准模块-行读取

# 读取文件第1行


>>>第1行: 学号,姓名,班级,古文,诗词,平均
# 程序运行结果

【例515】统计文件的行数。



1

2

3

4

5

6
#E0515.py

filepath = 'd:\\test\\05\\成绩.txt' 

count = 0

for index, line in enumerate(open(filepath,'rb')):

count += 1

print('文件行数为:', count)
# 【统计文件行数】

# 文件路径赋值

# 计数器初始化

# 循环读取文件行

# 行数累加


>>>文件行数为: 5
# 程序运行结果

程序第4行,函数enumerate()具有枚举功能,它可以遍历一个可迭代对象(如列表、字符串),并且将其组成一个索引序列,利用它可以同时获得索引和值。
5.1.4向文件写入数据
1. 覆盖写入文件
Python提供了2个文件写入函数,语法格式如下。



1

2

文件句柄.write(["单字符串"])

文件句柄.writelines(行字符串)
# 语法1:向文件写入一个字符串或字节流

# 语法2:将多个元素的字符串写入文件

函数write()是将字符串写入一个打开的文件。注意,首先,这里的字符串可以是二进制数据,而不仅仅是文字; 其次,write()函数不会在字符串结尾添加换行符(\n)。
【例516】用write()函数将字符串内容写入名为“诗歌1.txt”的文件。



1

2

3

4

5

6
#E0516.py

str1 = '白日依山尽,黄河入海流。\n欲穷千里目,更上一层楼。\n'

f = open('d:\\test\\05\\诗歌1.txt', 'w')

f.write(str1)

f.close()

print('写入成功,保存在d:\\test\\05\\诗歌1.txt')

# 【写入新文件1】

# \n为换行符

# 以写模式打开文件

# 字符串内容写入文件

# 关闭文件


>>>写入成功,保存在d:\test\05\诗歌1.txt
# 程序运行结果

程序第2行,由于write()函数不会在字符串结尾自动添加换行符(\n),因此字符串中必须根据需要人为加入换行符。
程序第3行,如果这个文件已经存在,那么源文件内容将会被新内容覆盖。
【例517】用writelines()函数将内容写入名为“登鹳雀楼out.txt”的文件。



1

2

3

4

5

6#E0517.py

s = ['白日依山尽,', '黄河入海流。', '欲穷千里目,', '更上一层楼。']

f = open('d:\\test\\05\\登鹳雀楼out.txt', 'w')

f.writelines(s)

f.close( )

print('列表写入成功。')#【写入文件2】

# 定义列表

# 写模式打开文件

# 列表写入文件

# 关闭文件


>>>列表写入成功。
# 程序运行结果

2. 追加写入文件
【例518】将字符串内容追加写入“诗歌1.txt”文件的结尾。



1

2

3

4

5
#E0518.py

f = open('d:\\test\\05\\诗歌1.txt', 'a+')

f.write('——王之涣《登鹳雀楼》\n')

f.close()

print('追加写入成功。')
# 【写入文件3】

# 以追加模式打开已存在的文件

# 字符串内容追加写入文件末尾

# 关闭文件


>>>追加写入成功。
# 程序运行结果

5.1.5文件属性检查
Python提供了许多常用的文件和目录操作方法,用户利用它们可以方便地重命名、删除文件和创建、删除、更改目录等。这主要是通过Python内置os模块来进行。
在进行文件操作前,先检查文件或目录是否存在,不然会使程序出错。有三种检查文件或目录是否存在的模块: os模块、try语句、pathlib模块。
1. 使用os.access()函数检查文件属性
使用os.access()函数可以判断文件的读写操作。语法格式如下。




os.access(路径, 操作模式)
# 文件属性检查的语法格式

函数返回值为True或者False。
【例519】利用access()函数检查文件各种读写属性。



1

2



3



4



5

>>>import os

>>>os.access("d:\\test\\05\\登鹳雀楼.txt", os.F_OK)

True

>>>os.access("d:\\test\\05\\登鹳雀楼.txt", os.R_OK)

True

>>>os.access("d:\\test\\05\\登鹳雀楼.txt", os.W_OK)

True

>>>os.access("d:\\test\\05\\登鹳雀楼.txt", os.X_OK)

True
# 导入标准模块-系统

# 参数os.F_OK检查文件路径是否存在



# 参数os.R_OK检查文件是否可读



# 参数os.W_OK检查文件是否可写



# 参数os.X_OK检查文件是否可加载


2. 使用try语句捕获程序异常
如果文件不存在或者文件不能读写,Python解释器会抛出一个程序异常,可以使用try语句来捕获这个异常。
【例520】利用try语句捕捉程序异常。



1

2

3

4

5

6

7

8
#E0520.py

try:

f = open("d:\\test\\05\\登鹳雀楼temp.txt")

for line in f.readlines():

print(line)

f.close()

except IOError:

print("文件不可读写!")
# 【捕获程序异常】

# 异常捕捉开始

# 访问不存在的文件:登鹳雀楼temp.txt

# 循环读取文件行

# 输出文件行

# 关闭文件

# 程序若正常则跳过本语句,若异常则执行下面语句

# 文件异常提示信息或其他处理语句

>>>文件不可读写!
# 程序运行结果

用try语句处理程序异常时,程序简单优雅,而且不需要引入其他模块。
3. 使用pathlib模块检查文件路径
可以使用pathlib模块检查文件路径和创建文件路径。
【例521】获取当前文件路径。



1

2

3


>>>from pathlib import Path

>>>p = Path("d:\\test\\05\\登鹳雀楼.txt")

>>>print(p)

d:\\test\\05\\登鹳雀楼.txt
# 导入标准模块-路径

# 获取文件位置

# 输出文件位置


【例522】获取当前目录路径。



1

2

3
>>>from pathlib import Path

>>>path = Path.cwd()

>>>print(path)

D:\\test
# 导入标准模块-路径

# 获取目录位置

# 输出目录位置



【例523】查看当前路径下的文件。



1

2

3

4

5

6
#E0523.py

from pathlib import Path

p = Path.cwd()

pys = p.glob('*.py')

for py in pys:

print(py)



# 导入标准模块-路径

# 导入路径标准模块pathlib

# 获取当前路径,查找符合规则的文件名

# 读取扩展名为.py的文件


>>>…(输出略)
# 程序运行结果

程序第4行,函数glob('*.py')表示查找文件扩展名为.py的文件,*号表示所有文件主名。glob()函数可以使用*、?、[ ]这三个匹配符。
5.2CSV文件读写
5.2.1CSV文件格式
1. CSV格式文件概述

CSV(逗号分隔值)文件以纯文本格式存储数据,CSV文件由任意数量的记录组成。每个记录为一行,行尾是换行符; 每个记录由一个或多个字段组成,字段之间最常见的分隔符有逗号、空格等。CSV文件广泛用于不同系统平台之间的数据交换,它主要解决数据格式不兼容的问题。
CSV文件是一个纯文本文件,所有数据都是字符串。CSV文件并不是表格,但是可以用Excel打开。CSV文件无法生成和保存公式,CSV文件不能指定字体颜色,没有多个工作表,不能嵌入图像和图表。CSV文件采用的字符集有ASCII、Unicode、EBCDIC、GB 2312等。
2. CSV格式文件规范
CSV文件并不存在通用的格式标准,国际因特网工程小组(IEIT)在RFC 4180(因特网标准文件)中提出的一些CSV格式文件的基础性描述,但是没有指定文件使用的字符编码格式,采用7位ASCII码是最基本的通用编码。目前大多数CSV文件遵循RFC 4180标准提出的基本要求,它们有以下规则。
(1) 回车换行符。
【例524】每一个记录都位于一个单独行,用回车换行符CRLF(即\r\n)分隔。



aaa,bbb,ccc CRLF

zzz,yyy,xxx CRLF

(2) 结尾回车换行符。
【例525】最后一行记录可以有结尾回车换行符,也可以没有。



aaa,bbb,ccc CRLF

zzz,yyy,xxx

(3) 标题头。
【例526】第1行可以有一个可选的标题头,格式和普通记录行格式相同。标题头要包含文件记录字段对应的名称,应该有和记录字段一样的数量。



field_name,field_name,field_name CRLF

aaa,bbb,ccc CRLF

zzz,yyy,xxx CRLF

(4) 字段分隔。
【例527】标题行和记录行中,存在一个或多个由半角逗号分隔的字段。整个文件中,每行应包含相同数量的字段,空格也是字段的一部分。每一行记录最后一个字段后面不能跟逗号。注意,字段之间一般用逗号分隔,也有用其他字符(如空格)分隔的CSV。



aaa,bbb,ccc

(5) 字段双引号。
【例528】每个字段之间可用或不用半角双引号(")括起来(注意,Excel不用双引号)。如果字段没有用引号括起来,那么该字段内部不能出现双引号字符。



"aaa","bbb","ccc" CRLF

zzz,yyy,xxx

【例529】字段中如果包含回车换行符、双引号或者逗号,该字段要用双引号括起来。



aaa, b CRLF

bb,"c,cc" CRLF

zzz,yyy,xxx

【例530】如果用双引号括字段,字段内双引号前必须加一个双引号进行转义。



""aaa","b""bb","ccc"

3. CSV格式文件应用案例
【例531】二手汽车价格如表52所示,将表格内容按CSV格式存储。


表52二手汽车价格表



出厂日期制造商型号说明价格
2015福特SUV2015款ac, abs, moon30000.00
2016雪佛兰前卫"扩展版"49000.00
2017雪佛兰前卫"扩展版, 大型"50000.00
2016Jeep大切诺基低价急待出售!


air, moon roof, loaded
47990.00

将表52内的数据以CSV格式表示。




出厂日期,制造商,型号,说明,价格

2015,福特,SUV2015款,"ac, abs, moon",30000.00

2016,雪佛兰,"前卫""扩展版""","",49000.00

2017,雪佛兰,"前卫""扩展版, 大型""","",50000.00

2016,Jeep,大切诺基,"低价急待出售!

air, moon roof, loaded",47990.00

5.2.2CSV文件读取
1. 用标准模块读取数据
Python标准库支持CSV文件的操作,读取CSV文件函数的语法格式如下。



csv.reader(csvfile, dialect='excel', **fmtparams)
# CSV文件读取的语法格式

参数csvfile为CSV文件或者列表对象。
参数dialect为指定CSV格式,dialect='excel'表示CSV文件格式与Excel格式相同。

参数**fmtparams为关键字参数,用于设置特殊的CSV文件格式(如空格分隔等)。
返回值csv.reader是一个可迭代对象(如列表)。

【例532】“梁山108将gbk.csv”文件内容如图51所示,读取和输出文件表头。


图51梁山108将gbk.csv文件内容(片段)





1

2

3

4

5

6
#E0532.py

import csv

with open("d:\\test\\05\\梁山108将gbk.csv") as f:

reader = csv.reader(f)

head_row = next(reader)

print(head_row)
# 【CSV文件读第1行】

# 导入标准模块

# 打开文件循环读取

# 创建读取对象

# 读文件第1行数据


>>>

['座次', '星宿', '诨名', '姓名', '初登场回数', '入山时回数', '梁山泊职位']
# 程序运行结果



程序第3行,没有指明CSV文件编码时,如果文件中有字符串,则采用GBK编码。
程序第4行,从CSV文件读出的数据都是字符串。
【例533】“梁山108将gbk.csv”文件内容如图51所示,读取CSV文件中第3列对应的所有数值,并且打印输出。



1

2

3

4

5

6
#E0533.py

import csv

with open("d:\\test\\05\\梁山108将gbk.csv") as f:

reader = csv.reader(f)

column=[row[3] for row in reader]

print(column)
# 【CSV文件读第3列】

# 导入标准模块-CSV读写

# 打开文件,绝对路径

# 创建读取对象

# 循环读文件第3列数据


>>> ['姓名', '宋江', '卢俊义', '吴用', …(输出略)
# 程序运行结果

程序第5行,这种方法需要事先知道列序号,如已知“姓名”在第3列。
2. 用pandas包读取数据
【例534】“梁山108将utf8.csv”文件内容如图51所示,利用pandas软件包(参见11.1节)读取和输出文件中“诨名”和“姓名”两列数据的前5行。



1

2

3




>>>import pandas as pd                            # 导入第三方包-数据分析

>>>data1 = pd.read_csv('d:\\test\\05\\梁山108将utf8.csv', usecols=['诨名', '姓名'], nrows=5)

>>>print(data1)

诨名姓名

0及时雨、呼保义、孝义黑三郎宋江

1玉麒麟卢俊义…(输出略)

程序第2行,pd.read_csv()是pandas读取CSV文件数据的函数; 参数usecols=['诨名', '姓名']表示只读取文件中的这两列; 参数nrows=5表示读取前5行的记录。
注意: pandas软件包路径前不能有r参数; 其次文件默认编码为UTF8。
【例535】“梁山108将gbk.csv”文件内容如图51所示,读取CSV文件中“姓名”列对应数据,并打印输出。



1

2

3

4

5

6

7

8

9

10
#E0535.py

import csv

import pandas as pd



filename = "d:\\test\\05\\梁山108将gbk.csv"

list1 = []

with open(filename, 'r') as file:

reader = csv.DictReader(file)

column = [row['姓名'] for row in reader]

print(column)
# 【CSV读指定列】

# 导入标准模块-CSV文件读写

# 导入第三方包-数据分析



# 文件为GBK编码(绝对路径)



# 打开文件

# 读取CSV文件到列表

# 循环读取列表的"姓名"列


>>>['宋江', '卢俊义', '吴用', '公孙胜', …(输出略)
# 程序运行结果

程序第8行,pandas包的csv.DictReader()与reader()函数类似,接收一个可迭代对象,返回的每一个列都放在一个字典的值内,字典的键则是列标题。
程序第9行,这种方法不需要事先知道列号,直接按表头名称“姓名”输出。
5.2.3CSV文件写入
1. 创建CSV文件
【例536】创建一个“学生gbk.csv”文件。



1

2

3

4

5

6

7

8

9

10

11

12
#E0536.py

import csv



csvPath = 'd:\\test\\05\\学生gbk.csv'

f = open(csvPath, 'w', encoding='gbk', newline='')

csv_writer = csv.writer(f)

csv_writer.writerow(['姓名', "年龄", "性别"])

csv_writer.writerow(['贾宝玉', '18', '男'])

csv_writer.writerow(['林黛玉', '16', '女'])

csv_writer.writerow(['薛宝钗', '18', '女'])

f.close()

print('文件创建成功!')
# 【CSV文件创建】

# 导入标准模块-CSV读写



# 设置CSV文件保存路径

# 【1.创建文件对象】

# 【2.构建写入对象】

# 【3.构建表头标签】

# 【4.写入行内容】





# 【5.关闭文件】


>>>文件创建成功!
# 程序运行结果

程序第5行,参数newline=''解决写入数据时写CSV文件出现多余空行的问题。
2. 向CSV文件追加数据
【例537】“成绩gbk.csv”文件如图52所示,在文件尾部写入一行新数据。


图52“成绩gbk.csv”文件内容




1

2

3

4

5

6

7
#E0537.py

import csv

with open("d:\\test\\05\\成绩gbk.csv", 'a') as f:

row = ['5', '薛蟠', '01', '20', '60', '0']

write = csv.writer(f)

write.writerow(row)

print("写入完成!")
# 【CSV文件写入数据】

# 导入标准模块-CSV读写

# 打开文件,添加模式

# 插入行赋值

# 创建写入对象

# 在文件尾写入一行数据


>>>写入完成!
# 程序运行结果

3. 两个CSV文件行内容合并
【例538】“成绩source.csv”文件存放所有源数据(见图52),另一个文件“成绩update.csv”存放更新数据(见图53)。两个文件表头相同,将“成绩update.csv”文件内容添加到“成绩source.csv”文件中。


图53“成绩update.csv”文件内容




1

2

3

4

5

6

7

8

9

10
#E0538.py

import csv

import pandas as pd



reader = csv.DictReader(open('d:\\test\\05\\成绩update.csv'))

header = reader.fieldnames

with open('d:\\test\\05\\成绩source.csv', 'a') as csv_file:

writer = csv.DictWriter(csv_file, fieldnames=header)

writer.writerows(reader)

print("写入完成!")
# 【CSV文件行合并】

# 导入标准模块-CSV读写

# 导入第三方包-数据分析



# 读取"成绩update.csv"文件,相对路径

# 获取表头标签信息

# 以追加模式打开"成绩source.csv"文件

# 批量写入新内容

# 内容写入文件


>>>写入完成!
# 程序运行结果

程序第5行,DictReader()为pandas的读取CSV文件函数。
程序第8行,DictWriter()为pandas的写入CSV文件函数。
4. 两个CSV文件列内容合并
【例539】源文件“成绩gbk.csv”如图54所示,扩展文件“成绩expand.csv”内容如图55所示。将两个文件进行列合并,合并后内容保存为“成绩out.csv”文件。


图54源文件“成绩gbk.csv”内容




图55扩展文件“成绩expand.csv”内容



从图54与图55可以发现,源文件中“姓名”一列与扩展文件中“姓名”一列的属性相同,内容相同,可以以这一列为主键,把扩展文件中的“性别”“年龄”这两列的数据添加到源文件中。如果扩展文件缺少某些行,则空着,最后源文件的行数不变。文件合并后内容如图56所示。


图56列合并后的“成绩out.csv”文件内容




1

2

3

4

5

6

7

8
#E0539.py # 【CSV文件列合并】

import pandas as pd                                          # 导入第三方包-数据分析



df1 = pd.read_csv('d:\\test\\05\\成绩gbk.csv', encoding='gbk')           # 【1.读入主文件】

df2 = pd.read_csv('d:\\test\\05\\成绩expand.csv', encoding='gbk')        # 【2.读入扩展文件】

outfile = pd.merge(df1, df2, how='left', left_on='姓名', right_on='姓名')   # 【3.设置合并主键】

outfile.to_csv('d:\\test\\05\\成绩out.csv', index=False, encoding='gbk')    # 【4.保存CSV文件】

print("文件合并完成!")

>>>文件合并完成! # 程序运行结果

程序第4行,df1=pd.read_csv()为读入CSV文件全部内容,返回值df1为pandas中的DataFrame二维表格结构,即源文件“成绩gbk.csv”为5行6列,df1也为5行6列。
程序第6行,pd.merge(df1, df2, how='left', left_on='姓名', right_on='姓名')中,参数how='left'表示两表拼接时以左侧为主键; 参数left_on='姓名'表示左侧主键名称为“姓名”; 参数right_on='姓名'表示右边的关联键名称也为“姓名”。
5. 解决CSV文件乱码问题
【例540】用UTF8编码写CSV文件后,如果用Excel打开时会显示乱码。



1

2

3

4

5

6

7

8

9

10#E0540.py

import csv



file = open('d:\\test\\05\\csv乱码.csv', 'w', encoding='utf-8', newline='')

wr = csv.writer(file)

wr.writerow(['姓名', '成绩'])

wr.writerow(['宝玉', 85])

wr.writerow(['黛玉', 90])

wr.writerow(['宝钗', 88])

file.close()

#【CSV-文件乱码】

# 导入标准模块



# 创建文件

# 创建写入对象

# 写入表头列名

# 写入数据行








11print('文件写入成功。')# 关闭文件句柄

>>>文件写入成功。# 程序运行结果

程序第4行,本语句写CSV文件后,用Windows自带的“记事本”程序打开CSV文件,则CSV文件显示正常,如图57所示; 如果用Excel打开刚刚写入的文件,就会发现文件内容是乱码,如图58所示,这说明Excel的默认编码存在问题。
UTF8编码分为两种: 一种是不带BOM(字节顺序编码)的标准形式; 另一种是带BOM的微软Excel格式。UTF8以字节为编码单元,它没有字节序的问题,因此它并不需要BOM。但是Excel的UTF8文件默认带BOM格式,即utf8sig(UTF8 with BOM)。写入CSV文件时,定义encoding='utf8sig'就可以解决Excel乱码问题。将E0540.py程序第4行修改为以下形式,就可以解决Excel乱码问题(结果见图59)。


图57记事本打开正常




图58Excel打开乱码




图59Excel打开正常






4
file = open('d:\\\\test\\\\05\\\\csv乱码解决.csv', 'w', encoding='utf8sig', newline='')


5.3Excel文件读写
5.3.1Excel模块操作函数
1. 第三方软件包基本功能

处理Excel文件的第三方软件包有xlrd/xlwt、xlutils、openpyxl、xlsxwriter、pandas、win32com等。由于设计目的不同,每个模块通常都着重于某一方面功能,各有所长。
xlrd和xlwt是应用非常广泛的Excel读写第三方包,它可以工作在任何平台,这意味着可以在Linux下读取Excel文件。xlrd和xlwt是两个相对独立的模块,它们主要是针对Office 2003或更早版本的xls文件格式。xlrd软件包可读取xls或xlsx文件; xlwt软件包只能写入xls文件,除了最基本的写入数据和公式,xlwt提供的功能非常少。

2. xlrd和xlwt的安装和导入
xlrd和xlwt是Python的第三方包,它们的安装方法如下。



1

2
>pip install xlrd -i https://pypi.tuna.tsinghua.edu.cn/simple

>pip install xlwt -i https://pypi.tuna.tsinghua.edu.cn/simple
# 清华大学镜像网站安装xlrd

# 清华大学镜像网站安装xlwt

可以通过help(xlrd)命令查看xlrd帮助信息,它会输出xlrd包中的一些模块,以及一些成员变量、常量、函数等。
3. Excel基本概念
Excel中工作簿(book)和工作表(sheet)的区别: 一个工作簿就是一个独立的文件,一个工作簿里可以有一个或者多个工作表,工作簿是工作表的集合。
每个工作表都有行和列,行以数字1开始,列以字母A开始。一个工作表由单元格(cell)组成,单元格可以存储数字和字符串。单元格以“行号”和“列号”进行定位。
注意: 读取Excel数据时,sheet号、行号、列号都是从索引0开始的。
4. Excel操作函数
xlrd软件包中,Excel文件的常用操作语句案例如表53所示。


表53xlrd软件包中Excel文件的常用操作语句案例



操作语句应用案例说明
import xlrd导入模块,只能读不能写,可读xlsx、xls文件
data = xlrd.open_workbook('路径和文件名.xlsx')
打开Excel文件读取数据
table = data.sheets()[0]
获取一个工作表,通过索引顺序获取
table = data.sheet_by_index(0)
获取一个工作表,通过索引顺序获取

table = data.sheet_by_name('Sheet1')
获取一个工作表,通过工作表名称获取

name = table.name
获取工作表名称
nrows = table.nrows
获取行数
nclos = table.ncols
获取列数
row_value= table.row_values(i)
获取某行整行的值
col_value = table.col_values(i)
获取某列整列的值
cell_A1 = table.cell(0, 0).value
获取第1行第1列单元格数据,方法1
cell_C4 = table.cell_value(2, 3)
获取第3行第4列单元格数据,方法2
cell_A1 = table.row(0)[0].value
获取第1行第1列单元格索引号,方法1
cell_A2 = table.col(1)[0].value
获取第2行第1列单元格索引号,方法2

for i in range(nrows):

print(table.row_values(i))

循环获取行的数据


for j in range(nclol):

print(table.col_values(j))


循环获取列的数据



rows = sheet.get_rows()

for row in rows:

print(row[0].value)


遍历每行数据,输出第1列数据



5.3.2Excel文件内容读取
1. 打开Excel工作簿



open_workbook()# 打开Excel工作簿


函数返回的是一个book对象,通过book对象可以获得一个sheet工作表。
【例541】“股票数据片段.xlsx”文件有两个工作表(股票数据片段1、股票年报数据片段2),内容如图510、图511所示,输出其中所有sheet的名称。


图510“股票数据片段.xlsx”中sheet1内容




图511“股票数据片段.xlsx”中sheet2内容





1

2

3

4

5

6

7
#E0541.py

import xlrd

excelPath = "d:\\test\\05\\股票数据片段.xlsx"

book = xlrd.open_workbook(excelPath, "r")

sheets = book.sheets()

for sheet in sheets:

print(sheet.name)
# 【读取Excel工作表名称】

# 导入第三方包-Excel读入

# 获取一个工作簿book对象

# 获取一个工作表sheet对象

# 遍历每一个工作表sheet名称

# 输出工作表名称


>>>

股票数据片段1

股票年报数据片段2
# 程序运行结果



2. 读取Excel单元格内数据



1

2
sheet.cell(行号, 列号)

sheet.cell_type(行号, 列号)
# 读取Excel单元格内数据(行列均从0起)

# 读取Excel单元格内数据类型(行列均从0起)

【例542】“股票数据片段.xlsx”文件中,sheet1内容如图510所示,sheet2内容如图511所示。读取和输出两个工作表中第4行第2列单元格中的数据。



1

2

3

4

5

6

7
#E0542.py

import xlrd

excelPath = "d:\\test\\05\\股票数据片段.xlsx"

book = xlrd.open_workbook(excelPath)

sheets = book.sheets()

for sheet in sheets:

print(sheet.cell_value(3, 1))
# 【读取单元格内容】

# 导入第三方包-Excel读入

# 获取一个book对象

# 获取一个sheet对象

# 遍历每一个sheet

# 读取sheet1和sheet2第4行第2列内容




>>>

7.22    康华生物
# 程序运行结果

# 注意,输出为竖行

【例543】“股票数据片段.xlsx”文件有两个工作表(股票数据片段1、股票年报数据片段2),内容如图510、图511所示,输出Excel工作表相关数据。



1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21
#E0543.py                                            # 【读取Excel综合案例】

import xlrd                                           # 导入第三方包-Excel读取

from datetime import date, datetime                       # 导入标准模块-日期时间



def read_excel():                                      # 【定义Excel读取函数】

workbook = xlrd.open_workbook('d:\\test\\05\\股票数据片段.xlsx')# 打开文件

print('全部工作表:', workbook.sheet_names())        # 获取所有工作表sheet

sheet2_name = workbook.sheet_names()[1]

sheet2 = workbook.sheet_by_index(1)                 # 根据sheet索引获取sheet内容

sheet2 = workbook.sheet_by_name('股票年报数据片段2')# 工作表名称赋值

print('当前工作表:', sheet2.name, sheet2.nrows, '行', sheet2.ncols, '列') # sheet名/行/列

rows = sheet2.row_values(3)                         # 获取第4行整行的值

cols = sheet2.col_values(3)                          # 获取第4列行整列的值

print('第4行全部内容:', rows)

print('第4列全部内容:', cols)

print('单元格第2行2列:', sheet2.cell(1, 1).value)     # 获取单元格第2行第2列内容

print('单元格第3行2列:', sheet2.cell_value(2, 1))    # 获取单元格第3行第2列内容


print('单元格数据类型:', sheet2.cell(1, 0).ctype)      # 获取单元格第2行第0列数据类型



if __name__ == '__main__':

read_excel()                                    # 调用Excel读取函数

>>>…(输出略)# 程序运行结果

5.3.3Excel文件写入数据
1. Excel写操作语法
第三方软件包xlwt中,Excel文件的常用操作语句应用案例如表54所示。


表54xlwt软件包中Excel文件的常用操作语句应用案例



操作语句应用案例说明
import xlwt导入写入库,只能写不能读,仅支持xls文件
book = xlwt.Workbook()新建一个Excel文件
sheet = book.add_sheet('红楼梦_sheet')
添加一个名称为“红楼梦”的工作表sheet
sheet.write(row, col, s)在单元格中写入数据
book.save('test.xls')
保存到当前目录下,注意,只能保存为xls文件

2. 创建Excel文件并写入数据
xlrd和xlwt是两个相对独立的模块,xlwt只提供写入方法,无法读取Excel中的数据,因此对已经写入的数据无法修改。除了最基本的写入数据和公式,xlwt提供的功能非常少,而且Excel文件只能保存为xls格式。
【例544】创建一个新文件“红楼梦excel_out.xls”,并写入相关数据。



1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

#E0544.py

import xlwt



stus = [['姓名', '年龄', '性别', '分数'],

['宝玉', 20, '男', 90],

['黛玉', 18, '女', 95],

['宝钗', 18, '女', 88],

['晴雯', 16, '女', 80]

]

book = xlwt.Workbook()

sheet = book.add_sheet('红楼梦_sheet')

row = 0

for stu in stus:

col = 0

for s in stu:

sheet.write(row, col, s)

col += 1

row += 1

book.save('d:\\test\\05\\红楼梦excel_out.xls')

print("Excel文件写入完成!")
# 【写入Excel数据】

# 导入第三方包-Excel写入(只能写不能读)



# 定义工作表数据(列表嵌套)











# 新建一个Excel文件

# 添加一个工作表sheet页



# 行循环控制



# 列循环控制

# 在单元格写入数据





# 保存Excel文件


>>> Excel文件写入完成!
# 程序运行结果如图5-12所示



图512创建的“红楼梦excel_out.xls”文件内容

5.4其他文件读写
5.4.1二进制文件读写
1. 二进制文件的解码和编码

文件在硬盘里以二进制格式存储,文件读到内存后需要转换为我们能看懂的数据格式。如果文件按照GBK格式的二进制字节码存储,而程序按照UTF8编码格式读取,就会产生乱码问题。在Python程序设计中,我们需要指定用什么模式打开文件(字符串或二进制字节码)。如果以二进制字节码读取文件,还需要指定读取数据时采用什么编码格式(ASCII、UTF8、GBK等),如果不指定读取编码格式,Python3默认编码为UTF8。
(1) 读二进制文件的解码操作decode()。二进制文件按照字节流的方式读写。从二进制文件中读取数据时,应先进行解码操作,decode()函数可以将字符串由其他编码转换为UTF8字节码,语法如下。



字符串变量名.decode([encoding="UTF8"] [,errors="strict"])# 二进制解码的语法格式

参数encoding为可选参数,表示要使用的编码,默认编码为UTF8。
参数errors为可选参数,表示设置错误处理方案。默认为strict,含义是编码错误时,引起一个UnicodeError异常提示。
(2) 写二进制文件的编码操作encode()。数据在写入二进制文件之前,应先进行编码操作,encode()函数的作用是将字符串由UTF8字节码转换为其他编码。




字符串变量名.encode([encoding="UTF8"] [,errors="strict"])# 二进制编码的语法格式

其参数与上面的解码函数相同。
【例545】字符串的编码和解码。



1

2

3



4

5



6

7



8

9


>>>a = '中国'

>>>a_utf8 = a.encode('UTF-8')

>>>a_utf8

b'\xe4\xb8\xad\xe5\x9b\xbd'

>>>a_unicode = a_utf8.decode('UTF-8')

>>>a_unicode

'中国'

>>>b_gbk = a_unicode.encode('GBK')

>>>b_gbk

b'\xd6\xd0\xb9\xfa'

>>>b_unicode = b_gbk.decode('GBK')

>>>b_unicode

'中国'
# 定义字符串

# 将字符串编码为UTF-8字节码





# 将UTF-8字节码解码为字符串





# 将UTF-8字节码转换为GBK字节码





# 将GBK字节码转换回字符串




2. 读取二进制文件
步骤1: 读取二进制文件时,使用open()函数打开文件,打开模式选择二进制数据读取模式"rb",使读取的数据流是二进制。
步骤2: 由于纯二进制文件内部不含任何数据结构信息,因此需要自定义二进制数据读取时的字节数。如数据类型是float32型时,对应数据的字节数就是4B。
步骤3: 使用循环语句块逐个读入n个字节数据。
【例546】读取二进制数据库文件“梁山108将.db”。



1

2

3

4

5

6

7

8

9

10

11

12

13
#E0546.py

import struct



with open("d:\\test\\05\\梁山108将.db", mode="rb") as f:

f.seek(3)

a = f.read(16)

print(type(a))

print(len(a))

print(a)

val_tuple = struct.unpack("<4H2I", a)

print(val_tuple)

val_list = list(val_tuple)

print(val_list)
# 【读取二进制文件】

# 导入标准模块-工具函数



# rb表示以二进制形式打开文件

# 移至指定字节位置

# 读入16字节

# 打印a类型

# 打印a内字节数

# 打印a内数据,以十六进制数显示

# 解析一个数据



# 将元组转为 list

# 关闭文件



>>>

16

b'ite format 3\x00\x10\x00\x01'

(29801, 8293, 28518, 28018, 857764961, 16781312)

[29801, 8293, 28518, 28018, 857764961, 16781312]
# 程序运行结果





程序第6行,16字节为4个unsigned short数据和2个unsigned int数据,字节排列为小端字节序(Little Endian),返回数据类型为元组。
程序第10行,如果解析一个数据,则应当读取与数据存储空间大小一致的字节数目,unpack仍然返回元组数据类型。
3. 写二进制文件
【例547】将字符串写入二进制文件。



1

2

3

4

5

6

7

8
#E0547.py

f = open('d:\\test\\05\\test1.dat', 'wb')

s1 = 'Python你好!'

s2= s1.encode('GBK')

f.write(s2)

f.close()

print('源字符串:', s1)

print('GBK字节码:', s2)
# 【写二进制文件】

# 以二进制覆盖写模式创建文件

# 设置字符串内容

# 字符串转换为GBK字节码

# 把字节码写入文件

# 关闭文件




>>>

源字符串: Python你好!

GBK字节码: b'Python\xc4\xe3\xba\xc3\xa3\xa1'
# 程序运行结果



此外,Python提供了pickle、struct、shutil等标准模块进行二进制文件读写操作。
5.4.2JSON文件读写
1. JSON文件数据类型
JSON(JavaScript对象符号)是一种轻量级的数据交换格式。JSON是ECMAScript(欧洲计算机协会)制定的一个规范,它采用独立于编程语言的文本格式来存储和表示数据。JSON采用文本格式。网址在向页面JavaScript传输数据时,JSON是最常用的数据格式之一。Python与JSON数据类型存在一些细小的差别。
2. 读取JSON文件中的数据
【例548】“工资.json”文件内容如下所示。



1

2

3

4

5

6

7
8[

{

"姓名": "关羽",

"年龄": 30,

"职业": "将军",

"工资": 10000

},

{



9

10

11

12

13

14

15

16

17

18

19

20


"姓名": "周仓",

"年龄": 25,

"职业": "副官",

"工资": 5000

},

{

"姓名": "糜芳",

"年龄": 40,

"职业": "文书",

"工资": 3000

}

]


【例549】方法1: 读取并输出“工资.json”文件内容。



1

2

3

4

5

6
#E0549.py

import json

f = open('d:\\test\\05\\工资.json')

data = json.load(f)

for dict_data in data:

print(dict_data)
# 【读取Json文件】

# 导入标准模块-Json文件读写

# 将数据导入文件句柄f

# 用loads()方法将字符串转换为列表

# 遍历data,打印列表中的每一个字典


>>>

{'姓名': '关羽', '年龄': 30, '职业': '将军', '工资': 10000}

{'姓名': '周仓', '年龄': 25, '职业': '副官', '工资': 5000}

{'姓名': '糜芳', '年龄': 40, '职业': '文书', '工资': 3000}


# 程序运行结果





【例550】方法2: 读取“工资.json”文件中某一键对应的值。



1

2

3

4

5

6
#E0550.py

import json

f = open('d:\\test\\05\\工资.json')

data = json.load(f)

for dict_data in data:

print(dict_data['姓名'], '工资='+str(dict_data['工资']))
# 【读取Json文件的值】

# 导入标准模块-Json读写

# 将数据导入文件句柄f

# 用loads()方法将字符串转换为列表

# 遍历data,输出列表中每一个字典


>>>

关羽 工资=10000

周仓 工资=5000

糜芳 工资=3000
# 程序运行结果




习题5
51简要说明文本文件读写的步骤。
52Python提供了哪些读取文本文件内容的函数?
53open()语句或with open()语句都可以实现文件读写,它们有哪些差别?
54简要说明CSV格式文件的特征。
55简要说明xlrd和xlwt软件包的特征。
56编程: 检查d:\\test\\05\\test_no.txt文件是否存在。
57编程: 数据文件test.txt内容如下所示,把数据读入到矩阵中。



1 2 2.5

3 4 4

7 8 7

注:  每个数据以空格分开。
58编程: 读取并打印“鸢尾花数据集.csv”。
59编程: 读取并打印“鸢尾花数据集.csv”数据集中第2行。
510编程: 将表55中的数据保存到“成绩.csv”文件。


表55题510表



学号姓名性别班级古文诗词
100001宝玉男1班8570
100002黛玉女2班8885