文章目录
- 第七章 文件和数据格式化
- 7.1 文件的使用
- 7.1.1 文件的类型
- 7.1.2 文件的打开和关闭
- 7.1.3 文件的读写
- 7.2 数据组织的维度
- 7.2.1 一维数据
- 7.2.2 二维数据
- 7.2.3 高维数据
- 7.3 一维数据的处理
- 7.3.1 一维数据的表示
- 7.3.2 一维数据的存储
- 7.3.3 一维数据的处理
- 7.4 二维数据的处理
- 7.4.1 二维数据的表示
- 7.4.2 二维数据的存储
- 7.4.3 二维数据的处理
- 7.5 实例解析——国家财政数据趋势演算
- 习题7
- 一、选择题
- 二、编程题
第七章 文件和数据格式化
7.1 文件的使用
文件时存储在辅助存储器上的一组数据序列,可以包含任何数据内容。概念上,文件是数据的集合和抽象。文件包括文本文件和二进制文件两种类型。
7.1.1 文件的类型
文本文件一般由单一特定编码的字符组成,如UTF-8编码,内容容易统一展示和阅读。
二进制文件直接由比特0和比特1组成,没有统一的字符编码,文本内部数据的组织格式与文件用途有关。二进制是信息按照非字符但有特定格式形成的文件,例如png格式的图片文件、avi格式的视频文件。
二进制文件和文本文件最主要的区别在于是否有统一的字符编码。
无论文件创建为文本文件或者二进制文件,都可以用“文本文件方式”和“二进制文件方式”打开,但打开后的操作不同。
# 一个文本文件,其内容为“计算机等级考试”,采用文本方式打开
# 注意:文本文件与Python程序文件放在同一个目录下
file = open("1.txt", mode="rt", encoding="UTF-8")
read_content = file.readline()
print(read_content)
file.close()
# 运行结果
计算机等级考试
# 一个文本文件,其内容为“计算机等级考试”,采用二进制方式打开
file = open("1.txt", mode="rb")
read_content = file.readline()
print(read_content)
file.close()
# 运行结果
b'\xe8\xae\xa1\xe7\xae\x97\xe6\x9c\xba\xe7\xad\x89\xe7\xba\xa7\xe8\x80\x83\xe8\xaf\x95'
采用文本方式读入文件,文件经过编码形成字符串,打印出有含义的字符;采用二进制方式打开文件,文件被解析为字节流。由于存在编码,字符串中的一个字符由多个字节表示。
7.1.2 文件的打开和关闭
Python对文本文件和二进制文件采用统一的操作步骤,即”打开—操作—关闭“,如下图所示。操作系统中的文件默认处于存储状态,首先需要将其打开,使得当前程序有权操作这个文件,打开不存在的文件系统可以创建这个文件。打开后的文件处于占用状态,此时,另一个进程不能操作这个文件。可以同做一组方式读取文件的内容或向文件写入内容,操作之后需要将文件关闭,关闭将释放对文件的控制是文件恢复或存储状态,此时,另一个进程能够操作文件。
Python通过open()函数打开一个文件,并返回一个操作这个文件的变量,语法格式如下:
<变量名> = open(<文件路径及文件名>,<打开模式>)
open()函数提供7种基本的打开模式:
打开模式 | 含义 |
---|---|
r | 只读模式,如果文件不存在,返回异常FileNotFoundError,默认值 |
w | 覆盖写模式,文件不存在则创建,存在则完全覆盖原文件 |
x | 创建写模式,文件不存在则创建,存在则返回异常FileExistsError |
a | 追加写模式,文件不存在则创建,存在则在原文件最后追加内容 |
b | 二进制文件模式 |
t | 文本文件模式,默认值 |
+ | 与/r/w/x/a一同使用,在原功能基础上增加同时读写功能 |
打开模式使用字符串方式表示,根据字符串定义,单引号或者双引号均可。上述打开模式中,‘x’、‘w’、‘x’、‘a’可以和‘b’、‘t’、‘+’组合使用,形成既表达读写又表达文件模式的方式。
打开文件有一些常用组合,使用方式如下:
# 以文本方式只读打开一个文件,读入后不能对文件进行修改
<变量名> = open(<文件名>, 'r') 或 <变量名> = open(<文件名>)
# 以文本方式可读写的打开一个文件,可以读入并修改文件
<变量名> = open(<文件名>, 'r+')
# 以文本方式打开一个空文件,准备写入一批内容,并保存为新文件
<变量名> = open(<文件名>, 'w')
# 以文本方式打开一个空文件或已有的文件,追加形式写入一批内容,更新原文件
<变量名> = open(<文件名>, 'a+')
# 以二进制方式只读打开一个文件,读入后不能对文件进行修改
<变量名> = open(<文件名>, 'rb')
文件试用结束后要用close()方法关闭,释放文件的使用授权,语法格式如下:
<变量名>.close()
7.1.3 文件的读写
根据打开方式不同,文件读写也会根据文本文件或二进制打开方式有所不同。
常用的文件读取方法如下:
方法 | 含义 |
---|---|
f.read(size=-1) | 从文件中读入整个文件内容,参数可选。如果给出,读入前size长度的字符串或字节流 |
f.readline(size=-1) | 从文件中读入一行内容,参数可选。如果给出,读入该行size长度的字符串或字节流 |
f.readlines(hint=-1) | 从文件中读入所有行,以每行为元素形成一个列表。参数可选,如果给出,读入hint行 |
f.seek(offset) | 改变当前文件操作指针的为啥,offset的值:0为文件开头,2为文件结尾 |
从文本文件逐行读入内容并进行处理是一个基本的文件操作需求。文本文件可以看成是由行组成的组合类型,因此,可以使用遍历循环逐行遍历文件,语法格式如下:
file = open(<文件路径及名称>, "r")
for line in file:
print(line) # 处理一行数据
f.close
常用的文件写入方法如下:
方法 | 含义 |
---|---|
f.write(s) | 向文件写入一个字符串或字节流 |
f.writelines(lines) | 将一个元素为字符串的列表整体写入文件 |
f.write(s)向文件写入字符串s,每次写入后,将会记录一个写入指针。放方法可以反复调用,再写入指针后分批写入内容,直至文件被关闭。
使用f.write(s)时,要显示的使用’\n’对写入文本进行分行,如果不进行分行,每次写入的字符串会被连接起来。
f = open("c.txt", "w")
f.write('新年都未有芳华\n')
f.write('二月初惊见草芽\n')
f.write('白雪却嫌春色晚\n')
f.write('故穿庭树作飞花\n')
f.close()
f.writelines(lines)直接将列表类型的个元素连接起来写入文件f
ls = ['新年都未有芳华\n','二月初惊见草芽\n','白雪却嫌春色晚\n','故穿庭树作飞花\n']
f = open("c.txt", "w")
f.writelines(ls)
f.close()
上述代码运行结果皆为:
新年都未有芳华
二月初惊见草芽
白雪却嫌春色晚
故穿庭树作飞花
7.2 数据组织的维度
一组数据在被计算机处理前需要进行一定的组织,表面数据之间的基本关系,进而形成”数据的维度“。根据数据的关系不同,数据组织可以分为:一维数据、二维数据和高维数据。
7.2.1 一维数据
一维数据由对等关系的有序或无需数据构成,采用线性方式组织,对应于数学中数组的概念。例如:中国的直辖市列表即可表示为一维数据,一维数据具有线性特点。
7.2.2 二维数据
二维数据,也称表格数据,有关联关系数据构成,采用二维表格方式组织,对应于数学中的矩阵,常见的表格都属于二维数据。例如:国家统计局发布的居民消费价格指数是二维数据。
7.2.3 高维数据
高维数据由键值对类型的数据构成,采用对象方式组织,可以多层嵌套。
高维数据在Web系统中十分常用,作为当今Internet组织内容的主要方式,高维数据衍生出HTML、XML、JSON等具体数据组织的语法结构。
7.3 一维数据的处理
7.3.1 一维数据的表示
一维数据是最简单的数据组织类型,由于是线性结构,在Python语言中主要采用列表形式表示。
一维数据的文件存储有多种方式,总体思路是采用特殊字符分隔各数据。采用存储方法包括4种:
(1)采用空格分隔元素,例如:
北京 上海 天津 重庆
(2)采用逗号分隔元素,例如:
北京,上海,天津,重庆
(3)采用换行分隔元素,例如:
北京
上海
天津
重庆
(4)其他特殊符号分隔,以分号分隔为例,例如:
北京;上海;天津;重庆
7.3.2 一维数据的存储
逗号分隔的存储格式叫做CSV格式(Comma-Separated Values,即逗号分隔值),它是一种通用的、相对简单的文件格式,在商业和科学上广泛应用,大部分编辑器都支持直接读入或保存文件为CSV格式。
一维数据保存成CSV格式后,各元素采用逗号分隔,形成一行。从Python表示到数据存储,需要将列表输出为CSV格式以及将CSV格式读入成列表对象。
列表对象输出为CSV格式文件方法如下,采用字符串的join()方法最为方便:
ls = ["北京", "上海", "天津", "重庆"]
file = open("city.csv", mode="w", encoding="UTF-8")
file.write(",".join(ls) + "\n")
file.close()
# 运行结果
北京,上海,天津,重庆
7.3.3 一维数据的处理
对一维数据进行处理首先需要从CSV格式文件读入一维数据,并将其表示为列表对象。
需要注意,从CSV文件中获得内容时,最后一个元素后面包含了一个换行符(“\n”)。对于数据的表达和使用来说,这个换行符是多余的,需要采用字符串的strip()方法去掉数据为不得换行符,进一步使用split()方法以逗号分割。
file = open("city.csv", mode="r", encoding="UTF-8")
ls = file.read().strip("\n").split(",")
file.close()
print(ls)
# 运行结果
['北京', '上海', '天津', '重庆']
7.4 二维数据的处理
7.4.1 二维数据的表示
二维数据由多个一维数据构成,可以看作是一维数据的组合形式。因此,二维数据可以采用二维列表来表示,即列表的每个元素对应二维数据的一行,这个元素本身也是列表类型,其内部各元素对应对应这行中的各列值。
7.4.2 二维数据的存储
二维数据有一维数据组成,用CSV格式文件存储。CSV文件的每行是一维数据,整个CSV文件是一个二维数据。
二维数据列表输出为CSV格式文件如下,采用遍历循环和字符串的join()方法相结合:
ls = [
['指标', '2014年', '2015年', '2016年'],
['居民消费价格指数', '102', '101.4', '102'],
['食品', '103.1', '102.3', '104.6'],
['烟酒及用品', '994', '102.1', '101.5'],
['衣着', '102.4', '102.7', '101.4'],
{'家庭设备用品', '101.2', '101', '100.5'},
['医疗保健和个人用品', '101.3', '102', '101.1'],
['交通和通信', '99.9', '98.3', '98.7'],
['娱乐教育文化', '101.9', '101.4', '101.6'],
['居住', '102', '100.7', '101.6'],
]
file = open("city.csv", mode="w", encoding="UTF-8")
for row in ls:
file.write(",".join(row)+"\n")
file.close()
# 运行结果
指标,2014年,2015年,2016年
居民消费价格指数,102,101.4,102
食品,103.1,102.3,104.6
烟酒及用品,994,102.1,101.5
衣着,102.4,102.7,101.4
家庭设备用品,101.2,101,100.5
医疗保健和个人用品,101.3,102,101.1
交通和通信,99.9,98.3,98.7
娱乐教育文化,101.9,101.4,101.6
居住,102,100.7,101.6
7.4.3 二维数据的处理
对二维数据进行处理首先需要从CSV格式文件读入二维数据,并将其表示为二维列表对象。借鉴一维数据读取方法,从CSV文件读入数据的方法如下:
ls = []
file = open("city.csv", mode="r", encoding="UTF-8")
for line in file:
ls.append(line.strip("\n").split(","))
file.close()
print(ls)
# 运行结果
[['指标', '2014年', '2015年', '2016年'], ['居民消费价格指数', '102', '101.4', '102'], ['食品', '103.1', '102.3', '104.6'], ['烟酒及用品', '994', '102.1', '101.5'], ['衣着', '102.4', '102.7', '101.4'], ['家庭设备用品', '101.2', '101', '100.5'], ['医疗保健和个人用品', '101.3', '102', '101.1'], ['交通和通信', '99.9', '98.3', '98.7'], ['娱乐教育文化', '101.9', '101.4', '101.6'], ['居住', '102', '100.7', '101.6']]
二维数据处理等同于二维列表的操作。与一维列表不同,二维列表一般需要借助循环遍历实现对每个数据的处理,基本代码如下:
for row in ls:
for item in row:
<对第row行第item列元素进行处理>
对二维数据进行格式化输出,打印成表格行状:
# 此处省略去从CSV获取数据到二维列表ls
for row in ls:
line = " "
for item in row:
line = line + "{:10.7}\t".format(item)
print(line)
# 运行结果
指标 2014年 2015年 2016年
居民消费价格指 102 101.4 102
食品 103.1 102.3 104.6
烟酒及用品 994 102.1 101.5
衣着 102.4 102.7 101.4
家庭设备用品 101.2 101 100.5
医疗保健和个人 101.3 102 101.1
交通和通信 99.9 98.3 98.7
娱乐教育文化 101.9 101.4 101.6
居住 102 100.7 101.6
7.5 实例解析——国家财政数据趋势演算
# FinancePredict.py
def parseCSV(filename):
dataNames, data = [], []
f = open(filename, 'r', encoding='utf-8')
for line in f:
splitedLine = line.strip().split(',')
if '指标' in splitedLine[0]:
years = [int(x[:-1]) for x in splitedLine[1:]]
else:
dataNames.append('{:10}'.format(splitedLine[0]))
data.append([float(x) for x in splitedLine[1:]])
f.close()
return years, dataNames, data
def means(data):
return sum(data) / len(data)
def linearRegression(xlist, ylist):
xmeans, ymeans = means(xlist), means(ylist)
bNumerator = - len(xlist) * xmeans * ymeans
bDenominator = - len(xlist) * xmeans ** 2
for x, y in zip(xlist, ylist):
bNumerator += x * y
bDenominator += x ** 2
b = bNumerator / bDenominator
a = ymeans - b * xmeans
return a, b
def calNewData(newyears, a, b):
return [(a + b * x) for x in newyears]
def showResults(years, dataNames, newDatas):
print('{:^60}'.format('国家财政收支线性估计'))
header = '指标 '
for year in years:
header += '{:10}'.format(year)
print(header)
for name, lineData in zip(dataNames, newDatas):
line = name
for data in lineData:
line += '{:>10.1f}'.format(data)
print(line)
def main():
newyears = [x + 2010 for x in range(7)]
newDatas = []
years, dataNames, datas = parseCSV('finance.csv')
for data in datas:
a, b = linearRegression(years, data)
newDatas.append(calNewData(newyears, a, b))
showResults(newyears, dataNames, newDatas)
main()
# 运行结果
国家财政收支线性估计
指标 2010 2011 2012 2013 2014 2015 2016
全部收入 105359.6 114550.1 123740.6 132931.0 142121.5 151312.0 160502.4
中央收入 48169.1 52283.8 56398.5 60513.2 64627.9 68742.7 72857.4
地方收入 57190.6 62266.3 67342.1 72417.8 77493.6 82569.3 87645.1
全部支出 122936.9 133645.7 144354.5 155063.3 165772.1 176480.9 187189.8
中央支出 19037.5 20390.9 21744.3 23097.7 24451.1 25804.5 27157.9
地方支出 103899.4 113254.8 122610.2 131965.6 141321.0 150676.4 160031.9
习题7
一、选择题
-
关于Python变量使用,下列说法中错误的是:_____
A 变量使用不必先声明
B 变量使用无需先创建和赋值
C 变量使用无需指定数据类型
D 可以使用del释放变量的内存资源正确答案:B
-
关于文件,下列说法中错误的是:_____
A 对已经关闭的文件进行读写操作会默认再次打开文件
B 对文件操作完成后即使不关闭程序也不会报错,所以可以不关闭文件
C 对于非空文本文件,read()返回字符串,readlines()返回列表
D file = open(filename, “rb”)表示以只读、二进制方式打开名为filename的文件
正确答案:A
-
给出以下代码:
fname = input("请输入要写入的文件:") fo = open(fname, "w+") ls = ["唐诗", "宋词", "元曲"] fo.writelines(ls) fo.seek(0) for line in fo: print(line) fo.close()
上述代码正确的是:_____
A 唐诗 B “唐诗” C 唐诗宋词元曲 D “唐诗宋词元曲”
宋词 “宋词”
元曲 “元曲”
正确答案:C
-
下列选项中不是Python对文件读操作方法的是:_____
A read() B readline() C readall() D readlines()
正确答案:C
-
将一个文件与程序的对象关联起来的过程,称为:_____
A 文件读取 B 文件写入 C 文件打开 D 文件关闭
正确答案:C
-
在读写文件之前,需要创建文件对象,采用的方法是:_____
A create B folder C open D File
正确答案:C
-
有一非空文本文件textfile.txt,执行下述代码:
file = open("textfile.txt", "r") for line in file.readline(): line += '[prefix]' file.close() for line in file.readline(): print(line)
程序输出的结果是:_____
A 逐行输出文件内容 B 逐行输出文件内容,但每行以[prefix]开头
C 报错 D 文件被清空,所以没有输出
正确答案:C
-
关于CSV文件处理,下述描述中错误的是:_____
A 因为CSV文件以半角逗号分隔每列数据,所以即使列数据为空也要保留逗号
B 对于包含英文半角逗号的数据,以CSV文件保存时需进行转码处理
C 因为CSV文件可以有Excel打开,所以是二进制文件
D 通常,CSV文件每行表示一个一维数据,多行表示二维数据
-
下列文件/语法格式通常不用作高维数据存储的一项是:_____
A HTML B XML C JSON D CSV
正确答案:D
-
采用Python语言对CSV文件写入,最可能采用的字符串方法是:_____
A strip() B split() C join() D format()
正确答案:C
二、编程题
-
统计次数。输入一个文件和一个字符串,统计该字符在文件中出现的次数。
# 定义一个函数,用于统计指定字符在指定文件中出现的次数 def countstr(filename, str1): # 将文件名赋值给一个变量 filenames = filename # 打开文件 f = open(filenames, 'r') # 初始化计数器 count = 0 # 逐行读取文件内容 for line in f: # 遍历每个字符 for i in line: # 如果字符与指定字符相同,则计数器加一 if i == str1: count += 1 # 输出结果 print(f'{str1}字符在{filename}文件中出现{count}次') # 定义一个主函数,用于输入文件名和指定字符,并调用 countstr 函数进行统计 def main(): filename = input("请输入文件名称:") str1 = input("请输入需要统计的字符:") countstr(filename, str1) # 调用主函数 main() # 运行结果 请输入文件名称:1.txt 请输入需要统计的字符:a a字符在1.txt文件中出现9次
-
替换大小写。假设有一个英文文本文件,编写一个程序读取其内容并将里面的大写字母变成小写字母,小写字母变成大写字母。
# 打开文件并读取内容 with open('1.txt', 'r') as f: text = f.read() # 将大小写字母互换 text = text.swapcase() # 打印结果 print(text) # 运行结果 AAAAAAAAA aaaaaaaaa BBBBBBBBBB bbbbbbbbbb CCCCCCCCCC cccccccccc DDDDDDDDDD dddddddddd
-
编写矩阵。编写一个程序,生成一个10x10的随机矩阵并保存为文件(空格分隔行向量,换行分隔列向量),再写程序将刚才保存的矩阵另存为CSV格式,用Excel或文本编辑器打开查看结果。
import random # 生成 10x10 的随机矩阵 matrix = [[random.randint(1, 100) for j in range(10)] for i in range(10)] # 将矩阵保存为文件(空格分隔行向量,换行分隔列向量) with open('matrix.txt', 'w') as f: # 遍历每一行 for row in matrix: # 将行向量转换为字符串,使用空格分隔 row_str = ' '.join([str(x) for x in row]) # 将该行字符串写入文件并换行 f.write(row_str + '\n') # 将矩阵另存为 CSV 格式 with open('matrix.csv', 'w') as f: # 遍历每一行 for row in matrix: # 将行向量转换为字符串,使用逗号分隔 row_str = ','.join([str(x) for x in row]) # 将该行字符串写入文件并换行 f.write(row_str + '\n') # 运行结果 # 保存为文件 75 74 4 2 2 13 42 17 56 54 21 36 71 33 96 1 51 64 37 44 33 15 4 28 91 80 58 6 33 78 1 84 88 63 22 65 1 49 11 43 5 77 100 28 51 54 58 72 83 76 79 53 80 60 31 19 59 92 60 68 2 97 63 53 52 70 69 84 19 69 77 57 59 51 9 66 48 20 98 24 89 69 38 68 12 27 36 96 82 55 26 92 16 6 38 65 87 36 4 60 #另存为 CSV 格式 75 74 4 2 2 13 42 17 56 54 21 36 71 33 96 1 51 64 37 44 33 15 4 28 91 80 58 6 33 78 1 84 88 63 22 65 1 49 11 43 5 77 100 28 51 54 58 72 83 76 79 53 80 60 31 19 59 92 60 68 2 97 63 53 52 70 69 84 19 69 77 57 59 51 9 66 48 20 98 24 89 69 38 68 12 27 36 96 82 55 26 92 16 6 38 65 87 36 4 60
-
替换源代码文件的大小写。编写一个程序,读取一个Python源代码文件,将文件中所有除保留字外的小写字母换成大写字母,生成后的文件要能够被Python解释器正确执行。
import keyword def convert_code(filename): with open(filename, mode='r', encoding="UTF-8") as f: source_code = f.read() # 获取Python的所有保留字 reserved_words = keyword.kwlist # 将小写字母转换成大写字母,但是不将保留字转换成大写字母 new_code = [] for line in source_code.split('\n'): new_line = [] for word in line.split(): if word.lower() in reserved_words: new_line.append(word) else: new_line.append(word.upper()) new_code.append(' '.join(new_line)) # 生成新的文件 new_filename = filename.split('.')[0] + '_new.py' with open(new_filename, mode='w', encoding="UTF-8") as f: f.write('\n'.join(new_code)) return new_filename convert_code("统计次数.py")
-
列表转换为CSV。编写一个程序,要去能够将元素为任意Python支持的类型(包括含有半角逗号的字符串)的列表转储为CSV,并能够重新正确解析为列表。
import csv import io def list_to_csv(data): # 创建一个字符串缓冲区 csv_data = io.StringIO() # 创建一个 CSV writer 对象 writer = csv.writer(csv_data) # 遍历列表中的每一行数据 for row in data: # 将每一行数据写入 CSV 文件中 writer.writerow(row) # 返回 CSV 格式的字符串 return csv_data.getvalue() def csv_to_list(csv_string): # 创建一个空列表,用于存储解析后的数据 data = [] # 创建一个字符串缓冲区,用于读取 CSV 格式的字符串 csv_data = io.StringIO(csv_string) # 创建一个 CSV reader 对象 reader = csv.reader(csv_data) # 遍历 CSV 文件中的每一行数据 for row in reader: # 将每一行数据添加到列表中 data.append(row) # 返回解析后的列表 return data # 测试代码 data = [[1, 'a', True], [2, 'b', False], [3, 'c,d', True]] csv_string = list_to_csv(data) print(csv_string) parsed_data = csv_to_list(csv_string) print(parsed_data) # 运行结果 1,a,True 2,b,False 3,"c,d",True [['1', 'a', 'True'], ['2', 'b', 'False'], ['3', 'c,d', 'True']]