Python学习笔记(七)

第七章 文件和数据格式化

文件的使用

文件概述

文件是一个存储在辅助存储器上的数据序列,可以包含任何数据内容。概念上,文件是数据的集合和抽象,类似地,函数是程序的集合和抽象。用文件形式组织和表达数据更有效也更为灵活。文件包括两种类型:文本文件和二进制文件。
二进制文件直接由比特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()


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容