第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) 操作模式用于控制文件打开方式,文件打开的操作模式及参数说明如表51所示。 表51文件打开的操作模式及参数说明 操 作 模 式参 数 说 明 r仅读,待打开的文件必须存在; 文件不存在时会返回异常FileNotFoundError w 仅写,若文件已存在,内容将先被清空; 若文件不存在则创建文件,不可读 续表 操 作 模 式参 数 说 明 a 仅写,若文件已存在,则在文件最后追加新内容; 若文件不存在则创建文件 r+ 可读,可写,可追加; 待打开的文件必须存在(“+”参数说明允许读和写) a+ 读写,若文件已存在,则内容不会被清空 w+ 读写,若文件已存在,则内容将先被清空 rb 仅读,读二进制文件; 待打开的文件必须存在(“b”参数说明读写二进制文件) wb 仅写,写二进制文件; 若文件已存在,则内容将先被清空 ab 仅写,写二进制文件; 若文件已存在,则内容不会被清空 【例51】打开当前目录下test.txt文件,对它进行覆盖写操作。 f = open("test.txt", "w")# 以写模式打开文件,f=文件句柄,相对路径 2. 关闭文件 文件使用结束后一定要关闭,这样才能保存文件内容,释放文件占用内存。 文件句柄.close()# 文件关闭的语法格式 3. 文件读取函数 Python提供了read()、readlines()和readline()三个文件读取函数。这三种函数都会把文件每行末尾的'\n'(换行符)也读进来,可以用splitlines()等函数删除换行符。 (1) read()函数一次读取文件的全部内容,返回值存放在一个大字符串中。它的优点是方便、简单、速度最快; 它的缺点是文件过大时,占用内存很大。 【例52】用read()函数读取“琴诗.txt”文件中全部内容。 1 2 3 >>>f = open("d:\\test\\05\\琴诗.txt", "r") >>>s = f.read( ) >>>s '[宋] 苏轼《琴诗》\n若言琴上有琴声,放在匣中何不鸣?\n若言声在指头上,何不于君指上听?\n'# 打开文件,f为文件句柄 # 读文件全部内容 # 输出内容为字符串 # \n为换行符 【例53】读取“琴诗.txt”文件中全部内容,并且删除文件中的回车符。 1 2 3 4 >>>f = open("d:\\test\\05\\琴诗.txt", "r") >>>s = f.read( ) >>>s = s.splitlines() >>>s ['[宋] 苏轼《琴诗》', '若言琴上有琴声,放在匣中何不鸣?', '若言声在指头上,何不于君指上听?'] # 打开文件,f为文件句柄 # 读文件全部内容 # 删除字符串中的换行符 # 输出内容已转换为列表 # 输出已经删除换行符 (2) readlines()函数一次读取全部文件,它自动将文件内容分解成一个大的列表,该列表可以用for循环进行处理。它的缺点是读取大文件时会比较占内存。 【例54】用readlines()函数读取“琴诗.txt”文件中全部内容。 1 2 >>>f = open("d:\\test\\05\\琴诗.txt", "r") >>>f.readlines( ) ['[宋] 苏轼《琴诗》\n', '若言琴上有琴声,放在匣中何不鸣?\n', '若言声在指头上,何不于君指上听?\n']# 打开文件,f为文件句柄 # 读文件全部内容 # 输出内容为列表 (3) readline()函数每次只读取一行,返回值是字符串。它的读取速度比readlines()慢得多,只有在没有足够内存一次读取整个文件时,才应该使用readline()函数。 【例55】用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()语句一次可以读取多个文件。 【例56】文件遍历方法1: 逐行读取文件内容。 1 2 3 4 #E0506.py with open('登鹳雀楼.txt') as file_obj: content = file_obj.read() print(content) # 【文件遍历1】 # 打开文件(相对路径,当前目录在d:\test\05) # 循环读取文件中每一行 # 输出行内容 >>>…(输出略) # 程序运行结果 【例57】文件遍历方法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=''为不换行输出 # 读取列表中行的内容 # 关闭文件 >>>…(输出略) # 程序运行结果 【例58】文件遍历方法3: 循环读取文件内容到列表,再输出列表。 1 2 3 #E0508.py for myList in open("登鹳雀楼.txt"): print(myList) # 【文件遍历3】 # 打开文件,循环输出列表内容(相对路径) # 输出列表内容 >>>…(输出略) # 程序运行结果 【例59】文件遍历方法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=''参数会多输出一些空行) # 关闭文件 >>>…(输出略) # 程序运行结果 【例510】文件遍历方法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语句判断文件是否结束 【例511】用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表示文件结尾。 【例512】获取文件指针位置。 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. 读取文件指定行 【例513】文件“成绩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行)。 【例514】用标准模块linecache中的getline()函数读出文件指定行。 1 2 3 4 #E0514.py import linecache s = linecache.getline('d:\\test\\05\\成绩.txt', 1) print('第1行:', s) # 【读文件指定行】 # 导入标准模块-行读取 # 读取文件第1行 >>>第1行: 学号,姓名,班级,古文,诗词,平均 # 程序运行结果 【例515】统计文件的行数。 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)。 【例516】用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行,如果这个文件已经存在,那么源文件内容将会被新内容覆盖。 【例517】用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. 追加写入文件 【例518】将字符串内容追加写入“诗歌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。 【例519】利用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语句来捕获这个异常。 【例520】利用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模块检查文件路径和创建文件路径。 【例521】获取当前文件路径。 1 2 3 >>>from pathlib import Path >>>p = Path("d:\\test\\05\\登鹳雀楼.txt") >>>print(p) d:\\test\\05\\登鹳雀楼.txt # 导入标准模块-路径 # 获取文件位置 # 输出文件位置 【例522】获取当前目录路径。 1 2 3 >>>from pathlib import Path >>>path = Path.cwd() >>>print(path) D:\\test # 导入标准模块-路径 # 获取目录位置 # 输出目录位置 【例523】查看当前路径下的文件。 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) 回车换行符。 【例524】每一个记录都位于一个单独行,用回车换行符CRLF(即\r\n)分隔。 aaa,bbb,ccc CRLF zzz,yyy,xxx CRLF (2) 结尾回车换行符。 【例525】最后一行记录可以有结尾回车换行符,也可以没有。 aaa,bbb,ccc CRLF zzz,yyy,xxx (3) 标题头。 【例526】第1行可以有一个可选的标题头,格式和普通记录行格式相同。标题头要包含文件记录字段对应的名称,应该有和记录字段一样的数量。 field_name,field_name,field_name CRLF aaa,bbb,ccc CRLF zzz,yyy,xxx CRLF (4) 字段分隔。 【例527】标题行和记录行中,存在一个或多个由半角逗号分隔的字段。整个文件中,每行应包含相同数量的字段,空格也是字段的一部分。每一行记录最后一个字段后面不能跟逗号。注意,字段之间一般用逗号分隔,也有用其他字符(如空格)分隔的CSV。 aaa,bbb,ccc (5) 字段双引号。 【例528】每个字段之间可用或不用半角双引号(")括起来(注意,Excel不用双引号)。如果字段没有用引号括起来,那么该字段内部不能出现双引号字符。 "aaa","bbb","ccc" CRLF zzz,yyy,xxx 【例529】字段中如果包含回车换行符、双引号或者逗号,该字段要用双引号括起来。 aaa, b CRLF bb,"c,cc" CRLF zzz,yyy,xxx 【例530】如果用双引号括字段,字段内双引号前必须加一个双引号进行转义。 ""aaa","b""bb","ccc" 3. CSV格式文件应用案例 【例531】二手汽车价格如表52所示,将表格内容按CSV格式存储。 表52二手汽车价格表 出厂日期制造商型号说明价格 2015福特SUV2015款ac, abs, moon30000.00 2016雪佛兰前卫"扩展版"49000.00 2017雪佛兰前卫"扩展版, 大型"50000.00 2016Jeep大切诺基低价急待出售! air, moon roof, loaded 47990.00 将表52内的数据以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是一个可迭代对象(如列表)。 【例532】“梁山108将gbk.csv”文件内容如图51所示,读取和输出文件表头。 图51梁山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文件读出的数据都是字符串。 【例533】“梁山108将gbk.csv”文件内容如图51所示,读取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包读取数据 【例534】“梁山108将utf8.csv”文件内容如图51所示,利用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参数; 其次文件默认编码为UTF8。 【例535】“梁山108将gbk.csv”文件内容如图51所示,读取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文件 【例536】创建一个“学生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文件追加数据 【例537】“成绩gbk.csv”文件如图52所示,在文件尾部写入一行新数据。 图52“成绩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文件行内容合并 【例538】“成绩source.csv”文件存放所有源数据(见图52),另一个文件“成绩update.csv”存放更新数据(见图53)。两个文件表头相同,将“成绩update.csv”文件内容添加到“成绩source.csv”文件中。 图53“成绩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文件列内容合并 【例539】源文件“成绩gbk.csv”如图54所示,扩展文件“成绩expand.csv”内容如图55所示。将两个文件进行列合并,合并后内容保存为“成绩out.csv”文件。 图54源文件“成绩gbk.csv”内容 图55扩展文件“成绩expand.csv”内容 从图54与图55可以发现,源文件中“姓名”一列与扩展文件中“姓名”一列的属性相同,内容相同,可以以这一列为主键,把扩展文件中的“性别”“年龄”这两列的数据添加到源文件中。如果扩展文件缺少某些行,则空着,最后源文件的行数不变。文件合并后内容如图56所示。 图56列合并后的“成绩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文件乱码问题 【例540】用UTF8编码写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文件显示正常,如图57所示; 如果用Excel打开刚刚写入的文件,就会发现文件内容是乱码,如图58所示,这说明Excel的默认编码存在问题。 UTF8编码分为两种: 一种是不带BOM(字节顺序编码)的标准形式; 另一种是带BOM的微软Excel格式。UTF8以字节为编码单元,它没有字节序的问题,因此它并不需要BOM。但是Excel的UTF8文件默认带BOM格式,即utf8sig(UTF8 with BOM)。写入CSV文件时,定义encoding='utf8sig'就可以解决Excel乱码问题。将E0540.py程序第4行修改为以下形式,就可以解决Excel乱码问题(结果见图59)。 图57记事本打开正常 图58Excel打开乱码 图59Excel打开正常 4 file = open('d:\\\\test\\\\05\\\\csv乱码解决.csv', 'w', encoding='utf8sig', 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文件的常用操作语句案例如表53所示。 表53xlrd软件包中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工作表。 【例541】“股票数据片段.xlsx”文件有两个工作表(股票数据片段1、股票年报数据片段2),内容如图510、图511所示,输出其中所有sheet的名称。 图510“股票数据片段.xlsx”中sheet1内容 图511“股票数据片段.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起) 【例542】“股票数据片段.xlsx”文件中,sheet1内容如图510所示,sheet2内容如图511所示。读取和输出两个工作表中第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 康华生物 # 程序运行结果 # 注意,输出为竖行 【例543】“股票数据片段.xlsx”文件有两个工作表(股票数据片段1、股票年报数据片段2),内容如图510、图511所示,输出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文件的常用操作语句应用案例如表54所示。 表54xlwt软件包中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格式。 【例544】创建一个新文件“红楼梦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所示 图512创建的“红楼梦excel_out.xls”文件内容 5.4其他文件读写 5.4.1二进制文件读写 1. 二进制文件的解码和编码 文件在硬盘里以二进制格式存储,文件读到内存后需要转换为我们能看懂的数据格式。如果文件按照GBK格式的二进制字节码存储,而程序按照UTF8编码格式读取,就会产生乱码问题。在Python程序设计中,我们需要指定用什么模式打开文件(字符串或二进制字节码)。如果以二进制字节码读取文件,还需要指定读取数据时采用什么编码格式(ASCII、UTF8、GBK等),如果不指定读取编码格式,Python3默认编码为UTF8。 (1) 读二进制文件的解码操作decode()。二进制文件按照字节流的方式读写。从二进制文件中读取数据时,应先进行解码操作,decode()函数可以将字符串由其他编码转换为UTF8字节码,语法如下。 字符串变量名.decode([encoding="UTF8"] [,errors="strict"])# 二进制解码的语法格式 参数encoding为可选参数,表示要使用的编码,默认编码为UTF8。 参数errors为可选参数,表示设置错误处理方案。默认为strict,含义是编码错误时,引起一个UnicodeError异常提示。 (2) 写二进制文件的编码操作encode()。数据在写入二进制文件之前,应先进行编码操作,encode()函数的作用是将字符串由UTF8字节码转换为其他编码。 字符串变量名.encode([encoding="UTF8"] [,errors="strict"])# 二进制编码的语法格式 其参数与上面的解码函数相同。 【例545】字符串的编码和解码。 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个字节数据。 【例546】读取二进制数据库文件“梁山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. 写二进制文件 【例547】将字符串写入二进制文件。 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文件中的数据 【例548】“工资.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 } ] 【例549】方法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} # 程序运行结果 【例550】方法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 51简要说明文本文件读写的步骤。 52Python提供了哪些读取文本文件内容的函数? 53open()语句或with open()语句都可以实现文件读写,它们有哪些差别? 54简要说明CSV格式文件的特征。 55简要说明xlrd和xlwt软件包的特征。 56编程: 检查d:\\test\\05\\test_no.txt文件是否存在。 57编程: 数据文件test.txt内容如下所示,把数据读入到矩阵中。 1 2 2.5 3 4 4 7 8 7 注: 每个数据以空格分开。 58编程: 读取并打印“鸢尾花数据集.csv”。 59编程: 读取并打印“鸢尾花数据集.csv”数据集中第2行。 510编程: 将表55中的数据保存到“成绩.csv”文件。 表55题510表 学号姓名性别班级古文诗词 100001宝玉男1班8570 100002黛玉女2班8885