我要悄悄学Python之文件与异常(二)

交心的不一定是真朋友。

遇到问题嘴上站在你身边和真正站在你身边,完全是两码事。

和别人起冲突时,沉默不语,事后才骂对方的朋友没必要深交;

会帮你道歉,但一旦你受到欺负,就为你出头的朋友,才是真的铁。

文件与异常(二)

在本篇专题中你可以学到:

  • 读取和写入文本文件
  • 处理数据集合
  • 处理命令行参数
  • 抛出和处理异常

迭代文件中的行

你已经知道了怎么样一次读取文件中的一行。然而,有更简单的方法。Python可以像处理每行是一个字符串的字符串容器那样对待一个输入文件。为了从文件中读取文本行,你可以使用for循环迭代文件对象。

infile = open('input.txt''r')
for line in infile:
 print(line)
infile.close()

在每个迭代的开始,循环变量line被赋值为包含文件中下一行文本的一个字符串。在循环体内部,你简单的处理文本即可。

然而,文件和容器之间有个关键区别。一旦文件被读取,你就不能再次迭代这个文件,除非先关闭文件并再次打开。

print函数的结尾是以换行符结束的,文件中的每一行的末尾也是一个换行符,因此,当我们的文件中包含一系列单词的输入文件,每行一个单词:

flask
django
python

在输入文件的行被输出到终端时,它们会被显示成每个单词之间有个空行:

flask

django

python

一般地,在使用输入字符串之前必须删除换行符。第一个文本行被读入时,字符串行的末尾是包含着换行符的:flaskn

为了删除换行符,对字符串应用rstrip方法:

line = line.rstrip()

从而得到新的字符串:flask

利用rstrip方法创建一个新的字符串,删除原字符串尾部的所有空白字符(空格、制表符、换行符)。例如,如果第三个文本行的单词python后面

跟着两个空格:python n

rstrip方法会同时删除两个空格和换行符:python

为了删除字符串尾部的指定字符,你可以把包含那些字符的字符串参数传递给rstrip方法。例如,我想要删除字符串尾部的一个圆点或一个问号,可以使用命令:

line = line.rstrip('.?')

下面的表格将更加细致的展示出rstrip的使用方法。

方法 返回值
s.lstrip()
s.lstrip(chars)
字符串s的新版本,其中s的左侧是空白字符(空格、制表符、换行符)都被删除。如果提供了参数chars,那么字符串chars中的字符都被删除,而不删除空白字符
s.rstrip()
s.strip(chars)
字符串s的新版本,其中s的右侧是空白字符(空格、制表符、换行符)都被删除。如果提供了参数chars,那么字符串chars中的字符都被删除,而不删除空白字符
s.strip()
s.strip(chars)
类似于lstriprstrip,只是在s的两侧删除字符

读取单词

有时候,你可能需要从一个文件中读取独立的单词。例如,假设我们的输入文件包含两行文本:

Mary had a little lamb,
whose fleece was white as snow.

我想把这些单词输出到终端,每行一个单词。

到目前为止,我想没有从一个文件中读取一个单词的方法,你必须首先读取一行,然后将其切分成独立的单元,这可以使用split方法完成。

worldList = line.split()

这里的split方法返回在每个空白字符处,对原始字符串进行切分得到子字符串的列表。

具体代码如下所示:

infile = open('word.txt''r')
for line in infile:
 line = line.strip('.,n')
 words = line.split()
 for word in words:
  print(word)
infile.close()

默认地,split方法使用空白字符作为分隔符。你也可以不同的分隔符切分为字符串。假如,单词之间使用冒号分隔,而不是空白符。

line = 'apples:pears:oranges:grapes'
substring = line.split(':')

上面的代码会将字符串切分成4个子字符串:

"apples" "pears" "oranges" "grapes"

注意,如果传递了分隔符作为参数,连续的分隔符不会被当作一个来处理,就像是没有提供参数一样。

line = 'apples:pears:oranges::grapes'
substring = line.split(':')

这样将会被分隔成5个子字符串:

"apples" "pears" "oranges" " " "grapes"

其中一个是空白字符。

下表将提供更加详细的split方法

方法 返回值
s.split()
s.split(sep)
s.split(sep, maxsplit)
从字符串s返回一个单词列表。如果提供了字符串sep,它被当作分隔符使用;否则,任何空白字符都会被当作分隔符。如果提供了maxsplit,就只分隔多次,得到最多maxsplit+1个单词
s.rstrip(sep, maxsplit) split一样,只不过这是从尾部开始分隔,而不是从前面开始
s.splitline() 返回一个字符串中独立行组成的列表,使用换行符n作为分隔符

读取字符

你可以使用read方法读取独立的字符,而不是读取一整行,read方法接收一个参数,用来指定要读取的字符数量。这个方法返回包含读取的字符的字符串,使用1作为参数时:

char = inputfile.read(1)

read方法返回包含文件中下一个字符串。或者,已经达到文件尾部就返回空字符串” “。下面的循环处理文件中的内容,每次一个字符:

inputfile = open('字符.txt''r')
char = inputfile.read(1)
while char != '':
 print(char)
 char = inputfile.read(1)
inputfile.close()
inputfile = open('字符.txt''r')
char = inputfile.read(1)
while char != '':
 print(char, end='')
 char = inputfile.read(1)
inputfile.close()

有换行效果与没有换行效果能够让你更加容易理解这段代码。

注意:read方法会读取和返回换行符,遇到它们时就结束当前行。

让我们写一个简单的程序,来计算文件中英语字母出现的次数。因为我们要维护计数的字母有26个,因此,我们可以使用一个包含26个用整数表示的计数器列表。

letterCounts = [0] * 26

字母”A”由counts[0]来维护,字母”B”由counts[1]来维护,以此类推,使用counts[25]来表示字母”Z”出现的次数。

我们不使用复杂的选择语句,可以使用ord函数来返回每个字符串的Unicode值。大写字母是按顺序编码的,从字母A的65到字母Z的90,把得到的值减去字母A的编码得到介于0至25之间的值,将其作为letterCounts列表的索引。

code = ord(char) - ord('A')
letterCounts = letterCounts[code] + 1

注意,所有小写字母在做统计之前都需要将其转换为大写字母。

letterCount = [0] * 26
inputfile = open('统计.txt''r')
char = inputfile.read(1)
while char != '':
 char = char.upper()
 if char >= 'A' and char <= 'Z':
  code = ord(char) - ord('A')
  letterCount[code] = letterCount[code] + 1
  char = inputfile.read(1)
print(letterCount)
inputfile.close()

注意:你所要统计的字符不能出现有任何的空格、换行与标点符号,否则将会进入死循环。因此,这段代码的bug还是比较多的,留给你们的任务是将这段代码的bug修复。

读取记录

一个文本文件可以包含数据记录的集合,每个记录中包含多个字段。例如,一个包含学生数据的文件可能包含身份证号、完整名字和年纪这些字段组成的记录。一个包含银行账号交易的文件可能包含由交易日期、描述和金额这些字段组成的记录。

比如下面的数据,每个记录包含两个字段:国家名字及人口。这样的数据的经典格式是每个字段存储为文件的一行,单个记录的所有字段连续存储:

China
1330044605
India
1147995898
Unite States
303824646

读取这样格式的数据是非常容易的。因为每个记录包含两个字段,我们从文件中读取两行来构成一个记录。这时我们可以使用readline方法和一个检查文件尾部(警戒值)的while循环:

infile = open('国家人口.txt''r')
line = infile.readline()
while line !='':
 countryName = line.rstrip()
 line = infile.readline()
 population = int(line)
 print('%s:%d' % (countryName, population))
 line = infile.readline()
infile.close()

输出结果,如下所示:

China:1330044605
India:1147995898
Unite States:303824646

文件处理实战

我们使用下面的程序来处理一段含文本和数字的数据记录

##
# 该程序读取一个文件,其中的行包含项目和价格,就像:
# item name 1:price1
# item name 2:price2
# 每个项目的名字以冒号结束。
# 该程序写入一个文件,其中项目左对齐而价格右对齐
# 最后一行是价格总和

# 提示输入文件和输出文件的名字
inputFileName = input('Input file: ')
outputFileName = input('Output file: ')

# 打开输入文件和输出文件
# 为了避免编码错误,可能需要设置encoding
inputFile = open(inputFileName, 'r', encoding='utf-8')
outputFile = open(outputFileName, 'w', encoding='utf-8')

# 读取输入并写入输出
total = 0.0

for line in inputFile:
 # 在冒号处切分记录
 print(line)
 parts = line.split(':')

 # 提取两个数据段
 item = parts[0]
 price = float(parts[1])

 # 增加total
 total += price

 # 写入输出
 outputFile.write('%-20s%10.2fn' % (item, price))

# 写入价格总和
outputFile.write('%-20s%10.2fn' % ('Total:', total))


# 关闭文件
inputFile.close()
outputFile.close()

# 成功提醒
print('处理完毕')

最后

迷茫不仅阻挡前方的去路,还让我们看不清未来的方向,使得我们越发焦虑,生活越发低沉……

面对每一次的失败,我们要相信:

这不是结束,甚至不是结束的开始,而是开始的结束

看完觉得有收获的,可以给啃书君点个【在看】,愿我们都能勇往直前,找到适合自己的道路。

我是啃书君,一个专注于学习的人,你懂的越多,你不懂的越多,更多精彩内容,我们下期再见!


原文始发于微信公众号(小志Codings):我要悄悄学Python之文件与异常(二)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/236613.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!