第五周 文件与字典
5.1 文件的基础
(1)Python中的字符串类型未编码— 使用encode()编码,decode()解码
(2)多行文本:【注意】如果在shell中直接输入带有换行符\n的字符串,则保持原样输出
(3)二进制文件:照片、音乐、视频、计算机程序等
优点:① 更加节省空间;② 采用二进制无格式存储;③ 更精确;④ 编码是变长的,灵活利用率高
不同的二进制文件,解码方式不同
5.2 文件的基本处理
(1)打开文件 —open() 建立磁盘上的文件与程序中的对象相关联,通过相关的文件对象获得
<variable>= open(<name>, <mode>)
磁盘文件名 打开模式
字符表示 |
打开模式描述 |
r |
只读。如果文件不存在,则输出错误 |
w |
只写(如果文件不存在,则自动创建文件) |
a |
附加到文件末尾 |
rb |
只读二进制文件,如果文件不存在,则输出错误 |
wb |
只写二进制文件,如果文件不存在,则自动创建文件 |
ab |
附加到二进制文件末尾 |
r+ |
读写 |
例:打开“numbers.dat”文本文件:
>>> infile = open(“numbers.dat”,“r”)
打开“music.mp3”的音频文件(二进制文件):
>>> infle = open(“music.mp3”,”rb”)
(2)文件操作:读取、写入、定位、追加、计算
① 文件读取:
操作名称 |
操作含义 |
read() |
返回值为包含整个文件内容的一个字符串 |
readline() |
返回值为文件下一行内容的字符串 |
readlines() |
返回值为整个文件内容的列表 每项是以换行为结尾的一行字符串 |
例:程序5.2.1
def main():
fname = input(“Enter filename:”)
infile = open(fname.“r”)
data = infile.read()
print(data)
for i in range(5):
line = infile.readline()
print(line[:-1])
main()
② 文件写入:
操作名称 |
操作含义 |
write() |
把含有本文数据或二进制数据块的字符串写入文件中 |
writelines() |
针对列表操作,接受一个字符串列表作为参数 将它们写入文件,并且行结束符不会被自动加入 |
例:
>>>> outfile = open(“outfile.txt”,”w”)
>>>> outfile.writelines([“Hello”, ” ”, ”world”])
>>>> outfile.close()
>>>> infile = open(“outfile.txt”, “r”)
>>>> infile.read()
‘Helloworld’
③ 文件遍历:如: 拷贝文件,根据数据文件定义行走路径,将文件由一种编码转换为另外一种编码
通用代码框架:
file = open(someFile, ”r”)
for line in file.readlines(): # 可简化为 for line in file:
#处理一行文件内容
file.close()
例:文件拷贝
程序5.2.2
def main():# 用户输入文件名 f1 = input("Enter a soucefile:").strip() f2 = input("Enter a soucefile:").strip() # 打开文件 infile = open(f1,"r") outfile = open(f2,"w") # 拷贝数据 countLines = countChars = 0 for line in infile: countLines += 1 countChars += len(line) outfile.write(line) print(countLines,"linesand",countChars,"chars copied") infile.close() outfile.close()main()
【运行结果】
Enter a soucefile:s.txt
Enter a soucefile:q.txt
1 lines and 15chars copied
(3)关闭文件 — close() 切断文件与程序的联系
写入磁盘,并释放文件缓冲区
5.3 文件实例
【实例一】根据文件date.txt中的数据,使用turtle库来动态绘制图形路径
元素1:路径前进像素数
元素2:转动方向,0为左,1为右
元素3:转动角度
元素4-6:绘制颜色的RGB值
例:第一行 — 绘制路径前进300个像素,向左转动144度,路径线段颜色为红色
【IPO】
输入:数据文件
处理:读取数据文件,并根据数据内容和要求绘制路径
输出:构建窗口,并输出图形
【程序实现】
程序5.3.1
# 根据数据文件在窗口中动态路径绘制
import turtle
def main():
# 设置窗口信息
turtle.title('数据驱动的动态路径绘制')
turtle.setup(800,800,0,0)
# 设置画笔
pen =turtle.Turtle()
pen.color("red")
pen.width(5)
pen.shape("turtle")
pen.speed(5)
# 读取文件
result = []
file = open("data.txt","r")
for line in file:
result.append(list(map(float, line.split(','))))
print(result)
for i inrange(len(result)):
pen.color(result[i][3],result[i][4],result[i][5])
pen.fd(result[i][0])
if result[i][1]:
pen.rt(result[i][2])
else:
pen.lt(result[i][2])
pen.goto(0,0)
if __name__ == '__main__':
main()
【运行结果】
【文件实例二】多文件读写 — 合并邮箱簿和电话簿文件
【IPO】输入:电话簿、邮箱地址簿文件
处理:将两个文件内容进行合并
输出:合并后的包含电话和邮箱地址的文件
【程序实现】
程序5.3.2
def main():
ftele1 = open('TeleAddressBook.txt', 'rb')
ftele2 = open('EmailAddressBook.txt', 'rb')
ftele1.readline() # 跳过第一行
ftele2.readline()
lines1 = ftele1.readlines()
lines2 = ftele2.readlines()
list1_name = []
list1_tele = []
list2_name = []
list2_email = []
for line in lines1: # 获取第一个文本中的姓名和电话信息
elements = line.split()
list1_name.append(str(elements[0].decode('gbk')))
list1_tele.append(str(elements[1].decode('gbk')))
# 将文本读出来的bytes转换为str类型
for line in lines2: # 获取第二个文本中的姓名和邮件信息
elements = line.split()
list2_name.append(str(elements[0].decode('gbk')))
list2_email.append(str(elements[1].decode('gbk')))
# 开始处理 #
lines = []
lines.append('姓名\t 电话 \t 邮箱\n')
# 按索引方式遍历姓名列表1
for i in range(len(list1_name)):
s = ''
if list1_name[i] in list2_name:
j = list2_name.index(list1_name[i])
# 找到姓名列表1对应列表2中姓名
s = '\t'.join([list1_name[i],list1_tele[i], list2_email[j]])
s += '\n'
else:
s = '\t'.join([list1_name[i],list1_tele[i], str(' ----- ')])
s += '\n'
lines.append(s)
# 处理姓名列表2中剩余的姓名
for i in range(len(list2_name)):
s = ''
if list2_name[i] not in list1_name:
s = '\t'.join([list2_name[i],str(' ----- '), list2_email[i]])
s += '\n'
lines.append(s)
ftele3 = open('AddressBook.txt', 'w')
ftele3.writelines(lines)
ftele3.close()
ftele1.close()
ftele2.close()
print("The addressBooks aremerged!")
if __name__ =="__main__":
main()
5.4 字典 — 针对非序列集合而提供的一种数据类型,<键> → <值>
(1)概念:通过任意键值查找集合中值信息的过程叫映射,python中通过字典实现映射
该集合以键位索引,同一个键信息对应一个值
(2)与序列类型的区别: ① 存取和访问的方式
② 键的类型
③ 排列方式
④ 映射值的方式
5.5 字典的操作:
(1)为字典增加一项,格式:
dictionaryName[key] = value
(2)访问字典中的值,格式:
dictionaryName[key]
若访问的值不存在,则返回错误信息
(3)删除字典中的一项,格式:
del dictionaryName[key]
(4)字典的遍历,格式:
for key in dictionaryName:
print(key +“ :” +str(dictionaryName[key]))
可遍历的内容:① 键 ② 值 ③ 项 ④ 键值对
for keys/values/itemsin dictionaryName.keys/values/items():
print(key/value/item)
for item, value in adict.items():
print(item,value)
(5)一个键是否在字典中:in或者not in
(6)字典不提供拼接和重复操作方法,其余操作符都可正常使用,字典是无序的
(7)字典方法:
方法名称 |
方法含义 |
keys():tuple |
返回一个包含字典所有key的列表 |
values():tuple |
返回一个包含字典所有value的列表 |
items():tuple |
返回一个包含所有键值的列表 |
clear():None |
删除字典中的所有项目 |
get(key):value |
返回字典中key对应的值 |
pop(key):val |
删除并返回字典中key对应的值 |
update(tuple) |
将字典中的键值添加到字典中 |
5.6 字典实例
【实例一】“统计词频”问题:
【问题描述】统计文章重复词语,有助于搜索引擎对网络信息的检索与归档
【IPO】 输入:从文件中读取一篇英文文章
处理:统计文件中每个单词的出现频率
输出:将最常出现的10个单词及出现次数,以下图表形式输出
【分析】①建立用于词频计算的空字典,对文本的每一行计算词频
② 从字典中获取数据对到列表中,对列表中的数据交换位置并排序
③ 用turtle库绘制统计词频结果图表
【程序实现】
程序5.6.1
import turtle
##全局变量##
#词频排列显示个数
count = 10
#单词频率数组-作为y轴数据
data = []
#单词数组-作为x轴数据
words = []
#y轴显示放大倍数-可以根据词频数量进行调节
yScale = 6
#x轴显示放大倍数-可以根据count数量进行调节
xScale = 30
################# Turtle Start ####################
#从点(x1,y1)到(x2,y2)绘制线段
def drawLine(t, x1, y1, x2, y2):
t.penup()
t.goto (x1, y1)
t.pendown()
t.goto (x2, y2)
# 在坐标(x,y)处写文字
def drawText(t, x, y, text):
t.penup()
t.goto (x, y)
t.pendown()
t.write(text)
def drawGraph(t):
#绘制x/y轴线
drawLine (t, 0, 0, 360, 0)
drawLine (t, 0, 300, 0, 0)
#x轴:坐标及描述
for x in range(count):
x=x+1 #向右移一位,为了不画在原点上
drawText(t, x*xScale-4, -20,(words[x-1]))
drawText(t, x*xScale-4,data[x-1]*yScale+10, data[x-1])
drawBar(t)
#绘制一个柱体
def drawRectangle(t, x, y):
x = x*xScale
y = y*yScale#放大倍数显示
drawLine(t, x-5, 0, x-5, y)
drawLine(t, x-5, y, x+5, y)
drawLine(t, x+5, y, x+5, 0)
drawLine(t, x+5, 0, x-5, 0)
#绘制多个柱体
def drawBar(t):
for i in range(count):
drawRectangle(t, i+1, data[i])
################# Turtle End ####################
#对文本的每一行计算词频的函数
def processLine(line, wordCounts):
#用空格替换标点符号
line = replacePunctuations(line)
#从每一行获取每个词
words = line.split()
for word in words:
if word in wordCounts:
wordCounts[word] += 1
else:
wordCounts[word] = 1
#空格替换标点的函数
def replacePunctuations(line):
for ch in line:
if ch in"~@#$%^&*()_-+=<>?/,.:;{}[]|\'""":
line = line.replace(ch, "")
return line
def main():
#用户输入一个文件名
filename = input("enter a filename:").strip()
infile = open(filename, "r")
#建立用于计算词频的空字典
wordCounts = {}
for line in infile:
processLine(line.lower(), wordCounts)
#从字典中获取数据对
pairs = list(wordCounts.items())
#列表中的数据对交换位置,数据对排序
items = [[x,y]for (y,x)in pairs]
items.sort()
#输出count个数词频结果
for i in range(len(items)-1, len(items)-count-1, -1):
print(items[i][1]+"\t"+str(items[i][0]))
data.append(items[i][0])
words.append(items[i][1])
infile.close()
#根据词频结果绘制柱状图
turtle.title('词频结果柱状图')
turtle.setup(900, 750, 0, 0)
t = turtle.Turtle()
t.hideturtle()
t.width(3)
drawGraph(t)
#调用main()函数
if __name__ == '__main__':
main()
【运行结果】
【实例二】使用字典结构优化程序5.3.2
程序5.6.2
#利用字典将两个通讯录文本合并为一个文本
def main():
ftele2=open('TeleAddressBook.txt','rb')
ftele1=open('EmailAddressBook.txt','rb')
ftele1.readline()#跳过第一行
ftele2.readline()
lines1 = ftele1.readlines()
lines2 = ftele2.readlines()
dic1 = {} #字典方式保存
dic2 = {}
for line in lines1:#获取第一个本文中的姓名和电话信息
elements = line.split()
#将文本读出来的bytes转换为str类型
dic1[elements[0]] =str(elements[1].decode('gbk'))
for line in lines2:#获取第二个本文中的姓名和电话信息
elements = line.split()
dic2[elements[0]] = str(elements[1].decode('gbk'))
###开始处理###
lines = []
lines.append('姓名\t 电话 \t 邮箱\n')
for key in dic1:
s= ''
if key in dic2.keys():
s ='\t'.join([str(key.decode('gbk')), dic1[key], dic2[key]])
s += '\n'
else:
s ='\t'.join([str(key.decode('gbk')), dic1[key], str(' ----- ')])
s += '\n'
lines.append(s)
for key in dic2:
s= ''
if key not in dic1.keys():
s ='\t'.join([str(key.decode('gbk')), str(' ----- '), dic2[key]])
s += '\n'
lines.append(s)
ftele3 = open('AddressBook.txt', 'w')
ftele3.writelines(lines)
ftele3.close()
ftele1.close()
ftele2.close()
print("The addressBooks aremerged!")
if __name__ == "__main__":
main()