所谓文件是指存储在硬盘上的各种文件,Python所读取的数据文件通常为文本格式,即可以使用文本编辑器来打开阅读。对于数据分析任务而言,数据文件是最为常见的数据获取途径。
1)数据文件
在讲解数据文件处理之前,先需要对数据文件做下说明。由于数据文件通常都很大,因此不建议大家直接使用Windows系统自带的记事本来打开,而可以尝试使用Sublime或者Editplus等专业文本编辑器。尤其是后者是免费软件,可以直接下载:
其次,数据文件未必一定表现的像一般的文本文件,在Windows中只有txt扩展名的文件才被默认看成是文本格式文件。如果更换了默认的扩展名,此时双击将不会自动使用记事本等文本编辑器打开,因此可以手工强行使用文本编辑器打开。
比如对于这个数据文件(下面练习会使用),存储的是用户对电影的评分信息:
电影评分数据文件https://www.njcie.com/python/pbda-data/7/u.zip下载后双击可能无法打开,或者打开了其他一些应用程序。
正确的打开方式是右击选择“Open with Sublime Text”:
打开效果为:
从中可以看出,Python所读取的数据文件就是文本格式,通常都采取一行表示一条记录,一行由多列组成,每列之间使用逗号、Tab或者空格分隔等形式。
2)文件读取
为方便处理,现将该数据文件 u.data 放在 C 盘的 temp 目录下。打开文件的代码为:
f = open('C:\\temp\\u.data')
print(f.read())
f.close()
输出内容很多,就是全部的文件内容。open函数可以打开文件,并创建文件类对象f,通过read方法获取全部数据,在文件访问完后,要及时使用close方法关闭文件。
更为简单常见的打开文件方法是:
with open('C:\\temp\\u.data') as f:
print(f.read())
效果一样,但是代码更简洁,而且还具有文件读取错误检测和处理完文件自动关闭的功能。
接来下,读取一行:
with open('C:\\temp\\u.data') as f:
print(f.readline())
输出为:uid mid rating timestamp,readline表示读取一行,这个第一行是标题行。
利用循环还可以读取多行:
with open('C:\\temp\\u.data') as f:
for i in range(5):
print(f.readline())
输出为:
uid mid rating timestamp
196 242 3 881250949
186 302 3 891717742
22 377 1 878887116
244 51 2 880606923
有了这些练习的基础,让我们来读取每行记录,并在首部增加一个从1开始累加的序号:
with open('C:\\temp\\u.data') as f:
i = 1
while True: # 反复循环,直至break退出
line = f.readline() # 读取下一行
if not line: # 如果读取完毕
break
print(str(i) + '\t' + line) # 输出
i += 1
输出的最后几行为:
99996 880 476 3 880175444
99997 716 204 5 879795543
99998 276 1090 1 874795795
99999 13 225 2 882399156
100000 12 203 3 879959583
这个循环读取的方式反复读取数据文件,一旦读取失败将会使得line字符串为空(Null),因此通过检测是否为空决定是否退出循环。读取的每一行都在输出前增加了一个不断累加的变量值,实现累加序号输出的效果。
也可以写为:
with open('C:\\temp\\u.data') as f:
i = 1
for line in f.readlines():
print(str(i) + '\t' + line)
i = i + 1
输出内容一样,readlines方法返回的是所有记录结果的字符串列表,因此无需判断是否需要结束文件读取。
虽然这些方法可以读取,但是该练习存在一个问题,总是在输出各行时,在每行间增加了一个空行。具体原因在于原始数据文件的每行结尾本来就有一个换行符,再加上print函数默认的输出完自动换行,导致了两次换行。
解决方法1:去除读取的每行尾的换行符:
with open('C:\\temp\\u.data') as f:
i = 1
for line in f.readlines():
print(str(i) + '\t' + line.strip())
i = i + 1
解决方法2:取消print函数自动换行功能:
with open('C:\\temp\\u.data') as f:
i = 1
for line in f.readlines():
print(str(i) + '\t' + line, end='')
i = i + 1
这些读取方法虽然可行,但是对于更大规模的数据文件而言,就可能存在读取性能低下的问题。因此,有时就需要采取一些读取性能更高的做法:
with open('C:\\temp\\u.data') as f:
i = 1
while True: # 反复循环,直至break退出
lines = f.readlines(10000) # 一次读取1万行
if not lines: # 如果读取完毕
break
for line in lines:
print(str(i) + '\t' + line.strip()) # 输出
i += 1
该代码输出内容一样。只是采取了一种称为“块读取”的方式,即一下读取多行记录。之所以能提升性能,主要原因在于读取文件需要访问硬盘等外存,这个读取本身相对很慢,不断的反复的访问硬盘往往会降低性能,所以要通过增大一次读取的数量和减少读取的频次,综合提高读取性能。这里一次读取为 1 万行,实际操作中可以根据情况灵活选择。
最后强调下含有中文信息的文件读取,有时文件名称和内容中存在中文字符,就需要指定字符集才能正确读取,如该数据文件含有中文:
文章关键词数据(中文)https://www.njcie.com/python/pbda-data/7/doc_kw.zip读取方法为:
with open('doc_kw.dat', encoding='UTF-8') as f:
for i in range(5):
print(f.readline().strip())
如果仍然存在字符集错误,可以尝试使用“UTF-8”、“GB2312”或者“GBK”中任意一个来替换现有的encoding属性值。
3)文件写入
先来看新建文件并写入:
with open('C:\\temp\\exec.txt', 'w') as f:
f.write('Hello!')
此时将会在 C 盘 temp 目录下建立一个 temp 文件夹,并生成一个 exec.txt 文件,内容就是“Hello”。open函数的第二个参数需要设定为写入模式 w(表示write,写入的意思),调用write方法将文本写入文件。注意,多次运行,该文件内容仍然还是不变,因为每次运行都会自动清空原有文件内容,这是 w 模式的特点。
要想实现追加写入,代码为:
with open('C:\\temp\\exec.txt', 'a') as f:
f.write('Hello!')
该文件打开模式为 a(表示append,追加的意思) ,因此反复运行这段代码,可以发现文件中的“Hello!”出现次数会越来越多。
默认情况下,追加总是在文件的最后添加内容。通过写入重定位,可以在文件中间任意位置追加内容。比如在文件最前面增加一个标题行:
with open('C:\\temp\\u.data', 'r+') as f:
old = f.read()
f.seek(0)
f.write('uid\tmid\trating\ttimestamp\n')
f.write(old)
文件打开模式采取了 r+ 表示读写模式,请注意 w+ 也是读写模式,但是会首先清空文件。使用seek可以进行定位,0表示重新定位到文件开头,此时写入就会从第一行开始。请注意,如果没有最后的写回原有数据的语句,将会导致开头写入的内容会覆盖部分起始内容,然后仍然是剩下的原始数据文件内容,原始数据将会丢失部分开头内容。
当然,seek 也可以实现在文件中间插入数据,不过建议大家考虑将文件数据全部读出,然后对该数据进行插入更新操作,最终一起整体写入文件,相对更为简单方便。
配套学习资源、慕课视频: