第七章 文件和数据格式化
文件的使用
文件概述
文件是一个存储在辅助存储器上的数据序列,可以包含任何数据内容。概念上,文件是数据的集合和抽象,类似地,函数是程序的集合和抽象。用文件形式组织和表达数据更有效也更为灵活。文件包括两种类型:文本文件和二进制文件。
二进制文件直接由比特0和比特1组成,没有统一字符编码,文件内部数据的组织格式与文件用途有关。二进制文件和文本文件最主要的区别在于是否有统一的字符编码
无论文件创建为文本文件或者二进制文件,都可以用“文本文件方式”和“二进制文件方式”打开,打开后的操作不同。
#理解文本文件和二进制文件的区别
textFile = open("f:/Code/Python/PythonCourse/7-1.txt","rt") #t表示文本文件方式
print(textFile.readline())
textFile.close()
binFile = open("f:/Code/Python/PythonCourse/7-1.txt","rb") #r表示二进制文件方式
print(binFile.readline())
binFile.close()
中国是个伟大的国家
b'\xd6\xd0\xb9\xfa\xca\xc7\xb8\xf6\xce\xb0\xb4\xf3\xb5\xc4\xb9\xfa\xbc\xd2'
采用文本方式读入文件,文件经过编码形成字符串,打印出有含义的字符;采用二进制方式打开文件,文件被解析为字节(byte)流。由于存在编码,字符串中的一个字符由2个字节表示。
文件的打开关闭
Python对文本文件和二进制文件采用统一的操作步骤,即“打开-操作-关闭”
Python通过解释器内置的open()函数打开一个文件,并实现该文件与一个程序变量的关联,open()函数格式如下:
<变量名> = open(<文件名>, <打开模式>)
open()函数有两个参数:文件名和打开模式。文件名可以是文件的实际名字,也可以是包含完整路径的名字
open()函数有7中基本的打开模式
文件的读写
根据打开方式不同可以对文件进行相应的读写操作,Python提供4个常用的文件内容读取方法
#文本文件逐行打印
fname = input("请输入要打开的文件: ")
fo = open(fname, "r")
for line in fo.readlines():
print(line)
fo.close()
请输入要打开的文件: f:/code/Python/PythonCourse/7-2.txt
中国是个伟大的国家!
中国地大物博
中国有五千年的文明
fname = input("请输入要打开的文件: ")
fo = open(fname, "r")
for line in fo:
print(line)
fo.close()
请输入要打开的文件: f:/code/Python/PythonCourse/7-2.txt
中国是个伟大的国家!
中国地大物博
中国有五千年的文明
如果程序需要逐行处理文件内容,建议采用上述代码格式:
fo = open(fname, "r")
for line in fo:
# 处理一行数据
fo.close()
Python提供3个与文件内容写入有关的方法
fname = input("请输入要写入的文件: ")
fo = open(fname, "w+")
ls = ["唐诗", "宋词", "元曲"]
fo.writelines(ls)
fo.close()
f=open(fname,"r")
for line in f:
print(line)
f.close()
请输入要写入的文件: f:/code/Python/PythonCourse/test.txt
唐诗宋词元曲
PIL库的使用
PIL库概述
PIL(Python Image Library)库是Python语言的第三方库,需要通过pip工具安装。
pip install pillow # 或者 pip3 install pillow
PIL库支持图像存储、显示和处理,它能够处理几乎所有图片格式,可以完成对图像的缩放、剪裁、叠加以及向图像添加线条、图像和文字等操作。
PIL库可以完成图像归档和图像处理两方面功能需求:
- 图像归档:对图像进行批处理、生成图像预览、图像格式转换等;
- 图像处理:图像基本处理、像素处理、颜色处理等。
PIL库Image类解析
在PIL中,任何一个图像文件都可以用Image对象表示
要加载一个图像文件,最简单的形式如下,之后所有操作对im起作用
from PIL import Image
im = Image.open("D:\\pycodes\\birdnest.jpg")
#GIF文件图像提取
#对一个GIF格式动态文件,提取其中各帧图像,并保存为文件。
from PIL import Image
im = Image.open('f:/PythonCourse/birdnest.gif') # 读入一个GIF文件
try:
im.save('f:/PythonCourse/picframe{:02d}.png'.format(im.tell()))
while True:
im.seek(im.tell()+1)
im.save('f:/PythonCourse/picframe{:02d}.png'.format(im.tell()))
except Exception as e:
print(e)
print("处理结束")
no more images in GIF file
处理结束
#图像的颜色交换
#交换图像中的颜色。可以通过分离RGB图片的三个颜色通道实现颜色交换
from PIL import Image
im = Image.open('f:/PythonCourse/birdnest.jpg')
r, g, b = im.split()
om = Image.merge("RGB", (b, g, r))
om.save('f:/PythonCourse/birdnestBGR.jpg')
#操作图像的每个像素点需要通过函数实现,采用lambda函数和point()方法搭配使用
im = Image.open('f:/PythonCourse/birdnest.jpg') #打开鸟巢文件
r, g, b = im.split() #获得RGB通道数据
newg = g.point(lambda i: i * 0.9) # 将G通道颜色值变为原来的0.9倍
newb = b.point(lambda i: i < 100) # 选择B通道值低于100的像素点
om = Image.merge(im.mode, (r, newg, newb)) # 将3个通道合形成新图像
om.save('f:/PythonCourse/birdnestMerge.jpg') #输出图片
图像的过滤和增强
PIL库的ImageFilter类和ImageEnhance类提供了过滤图像和增强图像的方法,共10种
利用Image类的filter()方法可以使用ImageFilter类,如下:
Image.filter(ImageFilter.fuction)
#图像的轮廓获取
from PIL import Image
from PIL import ImageFilter
im = Image.open('f:/PythonCourse/birdnest.jpg')
om = im.filter(ImageFilter.CONTOUR)
om.save('f:/PythonCourse/birdnestContour.jpg')
ImageEnhance类提供了更高级的图像增强需求,它提供调整色彩度、亮度、对比度、锐化等功能。
#图像的对比度增强。
#增强图像的对比度为初始的20倍。
from PIL import Image
from PIL import ImageEnhance
im = Image.open('f:/PythonCourse/birdnest.jpg')
om = ImageEnhance.Contrast(im)
om.enhance(20).save('f:/PythonCourse/birdnestEnContrast.jpg')
图像字符画绘制
位图图片是由不同颜色像素点组成的规则分布,如果采用字符串代替像素,图像就成为了字符画。
定义一个字符集,将这个字符集替代图像中的像素点。
ascii_char =list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjf1234568795t/\|()1{}[]?-_+~<>i!;:,\"^`'.")
定义彩色向灰度的转换公式如下,其中R、G、B分别是像素点的RGB颜色值:
Gray = R * 0.2126 + G * 0.7152 + B * 0.0722
因此,像素的RGB颜色值与字符集的对应函数如下:
def get_char(r, b, g, alpha=256):
if alpha == 0:
return ' '
gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)
unit = 256 / len(ascii_char)
return ascii_char[gray//unit]
from PIL import Image
ascii_char = list('"$%_&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-/+@<>i!;:,\^`.')
def get_char(r, b, g, alpha=256):
if alpha == 0:
return ' '
gray = int(0.2126 * r + 0.7152 * g + 0.0722 * b)
unit = 256 / len(ascii_char)
return ascii_char[int(gray//unit)]
def main():
im = Image.open('f:/PythonCourse/pic.jpg')
WIDTH, HEIGHT = 100, 60
im = im.resize((WIDTH, HEIGHT))
txt = ""
for i in range(HEIGHT):
for j in range(WIDTH):
txt += get_char(*im.getpixel((j, i)))
txt += '\n'
fo = open("f:/PythonCourse/pic_char.txt","w")
fo.write(txt)
fo.close()
main()
一二维数据格式化和处理
数据组织的维度
一维数据由对等关系的有序或无序数据构成,采用线性方式组织,对应于数学中的数组和集合等概念。
二维数据,也称表格数据,由关联关系数据构成,采用表格方式组织,对应于数学中的矩阵,常见的表格都属于二维数据。
高维数据由键值对类型的数据构成,采用对象方式组织,属于整合度更好的数据组织方式。高维数据在网络系统中十分常用,HTML、XML、JSON等都是高维数据组织的语法结构
一二维数据的存储格式
一维数据是最简单的数据组织类型,有多种存储格式,常用特殊字符分隔:
(1)用一个或多个空格分隔,例如:
中国 美国 日本 德国 法国 英国 意大利
(2)用逗号分隔,例如:
中国,美国,日本,德国,法国,英国,意大利
(3)用其他符号或符号组合分隔,建议采用不出现在数据中的特殊符号
中国; 美国; 日本; 德国; 法国; 英国; 意大利
逗号分割数值的存储格式叫做CSV格式(Comma-Separated Values,即逗号分隔值),它是一种通用的、相对简单的文件格式,在商业和科学上广泛应用,尤其应用在程序之间转移表格数据。
(1)纯文本格式,通过单一编码表示字符;
(2)以行为单位,开头不留空行,行之间没有空行;
(3)每行表示一个一维数据,多行表示二维数据;
(4)以逗号分隔每列数据,列数据为空也要保留逗号;
(5)可以包含或不包含列名,包含时列名放置在文件第一行。
二维数据采用CSV存储后的内容如下:
城市,环比,同比,定基
北京,101.5,120.7,121.4
上海,101.2,127.3,127.8
广州,101.3,119.4,120
深圳,102,140.9,145.5
沈阳,100.1,101.4,101.6
CSV格式存储的文件一般采用.csv为扩展名,可以通过Windows平台上的记事本或微软Office Excel工具打开,也可以在其他操作系统平台上用文本编辑工具打开。
一二维数据的表示和读写
CSV文件的每一行是一维数据,可以使用Python中的列表类型表示,整个CSV文件是一个二维数据,由表示每一行的列表类型作为元素,组成一个二维列表。
[
['城市', '环比', '同比', '定基'],
['北京', '101.5', '120.7', '121.4'],
['上海', '101.2', '127.3', '127.8'],
['广州', '101.3', '119.4', '120.0'],
['深圳', '102.0', '140.9', '145.5'],
['沈阳', '100.1', '101.4', '101.6']
]
l = [
['城市', '环比', '同比', '定基'],
['北京', '101.5', '120.7', '121.4'],
['上海', '101.2', '127.3', '127.8'],
['广州', '101.3', '119.4', '120.0'],
['深圳', '102.0', '140.9', '145.5'],
['沈阳', '100.1', '101.4', '101.6']
]
f = open("f:/PythonCourse/price2016.csv","w")
for ll in l:
f.write(",".join(ll)+ "\n")
f.close()
#导入CSV格式数据到列表
fo = open("f:/PythonCourse/price2016.csv", "r")
ls = []
for line in fo:
line = line.replace("\n","")
ls.append(line.split(","))
print(ls)
fo.close()
[['城市', '环比', '同比', '定基'], ['北京', '101.5', '120.7', '121.4'], ['上海', '101.2', '127.3', '127.8'], ['广州', '101.3', '119.4', '120.0'], ['深圳', '102.0', '140.9', '145.5'], ['沈阳', '100.1', '101.4', '101.6']]
需要注意,以split(",")方法从CSV文件中获得内容时,每行最后一个元素后面包含了一个换行符("\n")。对于数据的表达和使用来说,这个换行符是多余的,可以通过使用字符串的replace()方法将其去掉,如第4行。
#逐行处理CSV格式数据。
fo = open("f:/PythonCourse/price2016.csv", "r")
ls = []
for line in fo:
line = line.replace("\n","")
ls = line.split(",")
lns = ""
for s in ls:
lns += "{}\t".format(s)
print(lns)
fo.close()
城市 环比 同比 定基
北京 101.5 120.7 121.4
上海 101.2 127.3 127.8
广州 101.3 119.4 120.0
深圳 102.0 140.9 145.5
沈阳 100.1 101.4 101.6
#一维数据写入CSV文件
fo = open("f:/PythonCourse/price2016bj.csv", "w")
ls = ['北京', '101.5', '120.7', '121.4']
fo.write(",".join(ls)+ "\n")
fo.close()
对于列表中存储的二维数据,可以通过循环写入一维数据的方式写入CSV文件,参考代码样式如下:
for row in ls:
<输出文件>.write(",".join(row)+"\n")
#二维数据写入CSV文件
fr = open("f:/PythonCourse/price2016.csv", "r")
fw = open("f:/PythonCourse/price2016out.csv", "w")
ls = []
for line in fr: #将CSV文件中的二维数据读入到列表变量
line = line.replace("\n","")
ls.append(line.split(","))
for i in range(len(ls)): #遍历列表变量计算百分数
for j in range(len(ls[i])):
if ls[i][j].replace(".","").isnumeric():
ls[i][j] = "{:.2}%".format(float(ls[i][j])/100)
for row in ls: #将列表变量中的二位数据输出到CSV文件
print(row)
fw.write(",".join(row)+"\n")
fr.close()
fw.close()
['城市', '环比', '同比', '定基']
['北京', '1.0%', '1.2%', '1.2%']
['上海', '1.0%', '1.3%', '1.3%']
['广州', '1.0%', '1.2%', '1.2%']
['深圳', '1.0%', '1.4%', '1.5%']
['沈阳', '1.0%', '1.0%', '1.0%']
CSV格式的HTML展示
展示二位数据的对应的HTML代码:
<!DOCTYPE HTML>
<html>
<body>
<meta charset=utf-8>
<h2 align=center>2016年7月部分大中城市新建住宅价格指数</h2>
<table border='1' align=center width=70%>
<tr bgcolor='orange'>
<th width="25%">城市</th>
<th width="25%">环比</th>
<th width="25%">同比</th>
<th width="25%">定基</th>
</tr>
<tr><td>北京</td><td>101.5</td><td>120.7</td><td>121.4</td></tr>
<tr><td>上海</td><td>101.2</td><td>127.3</td><td>127.8</td></tr>
<tr><td>广州</td><td>101.3</td><td>119.4</td><td>120.0</td></tr>
<tr><td>深圳</td><td>102.0</td><td>140.9</td><td>145.5</td></tr>
<tr><td>沈阳</td><td>100.1</td><td>101.4</td><td>101.6</td></tr>
</table>
</body>
</html>
seg1 = '''
<!DOCTYPE HTML>\n<html>\n<body>\n<meta charset=gb2312>
<h2 align=center>2016年7月部分大中城市新建住宅价格指数</h2>
<table border='1' align="center" width=70%>
<tr bgcolor='orange'>\n '''
seg2 = "</tr>\n"
seg3 = "</table>\n</body>\n</html>"
def fill_data(locls):
seg = '<tr><td align="center">{}</td><td align="center">\
{}</td><td align="center">{}</td><td align="center">\
{}</td></tr>\n'.format(*locls)
return seg
fr = open("f:/PythonCourse/price2016.csv", "r")
ls = []
for line in fr:
line = line.replace("\n","")
ls.append(line.split(","))
print(ls)
fr.close()
fw = open("f:/PythonCourse/price2016.html", "w")
fw.write(seg1)
fw.write('<th width="25%">{}</th>\n<th width="25%">{}</th>\n<th width="25%">{}</th>\n<th width="25%">{}</th>\n'.format(*ls[0]))
fw.write(seg2)
for i in range(len(ls)-1):
fw.write(fill_data(ls[i+1]))
fw.write(seg3)
fw.close()
[['城市', '环比', '同比', '定基'], ['北京', '101.5', '120.7', '121.4'], ['上海', '101.2', '127.3', '127.8'], ['广州', '101.3', '119.4', '120.0'], ['深圳', '102.0', '140.9', '145.5'], ['沈阳', '100.1', '101.4', '101.6']]
高维数据的格式化
与一维二维数据不同,高维数据能展示数据间更为复杂的组织关系。为了保持灵活性,表示高维数据不采用任何结构形式,仅采用最基本的二元关系,即键值对。万维网是高维数据最成功的典型应用。
JSON格式可以对高维数据进行表达和存储。JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于阅读和理解。JSON格式表达键值对基本格式如下,键值对都保存在双引号中:
"key" : "value"
当多个键值对放在一起时,JSON有如下一些约定:
- 数据保存在键值对中;
- 键值对之间由逗号分隔;
- 括号用于保存键值对数据组成的对象;
- 方括号用于保存键值对数据组成的数组。
"本书作者" : [
{ "姓氏" : "嵩",
"名字" : "天",
"单位" : "北京理工大学" },
{ "姓氏" : "礼",
"名字" : "欣",
"单位" : "北京理工大学" },
{ "姓氏" : "黄",
"名字" : "天羽",
"单位" : "北京理工大学" }
]
json库的使用
Json库的概述
json库主要包括两类函数:操作类函数和解析类函数
- 操作类函数主要完成外部JSON格式和程序内部数据类型之间的转换功能
- 解析类函数主要用于解析键值对内容。
Json库的解析
dumps()和loads()分别对应编码和解码功能。
import json
dt = {'b':2,'c':4,'a':6}
s1 = json.dumps(dt) #dumps返回JSON格式的字符串类型
s2 = json.dumps(dt,sort_keys=True,indent=4)
print(s1)
print(s2)
print(s1==s2)
dt2 = json.loads(s2)
print(dt2, type(dt2))
{"b": 2, "c": 4, "a": 6}
{
"a": 6,
"b": 2,
"c": 4
}
False
{'a': 6, 'b': 2, 'c': 4} <class 'dict'>
CSV和JSON格式相互转换
CSV格式常用于一二维数据表示和存储,JSON也可以表示一二维数据。在网络信息传输中,可能需要统一表示方式,因此,需要在CSV和JSON格式间进行相互转换。
#将CSV转换成JSON格式的代码如下
import json
fr = open("f:/PythonCourse/price2016.csv", "r")
ls = []
for line in fr:
line = line.replace("\n","")
ls.append(line.split(','))
fr.close()
fw = open("f:/PythonCourse/price2016.json", "w")
for i in range(1,len(ls)):
ls[i] = dict(zip(ls[0], ls[i]))
json.dump(ls[1:],fw, sort_keys=True, indent=4)
fw.close()
#将二维JSON格式数据转换成CSV格式
import json
fr = open("f:/PythonCourse/price2016.json", "r")
ls = json.load(fr)
data = [ list(ls[0].keys()) ]
for item in ls:
data.append(list(item.values()))
fr.close()
fw = open("f:/PythonCourse/price2016_from_json.csv", "w")
for item in data:
fw.write(",".join(item) + "\n")
fw.close()