第七章 文件和數(shù)據(jù)格式化
文件的使用
文件概述
文件是一個存儲在輔助存儲器上的數(shù)據(jù)序列坚芜,可以包含任何數(shù)據(jù)內(nèi)容伸辟。概念上,文件是數(shù)據(jù)的集合和抽象,類似地糕非,函數(shù)是程序的集合和抽象呢燥。用文件形式組織和表達數(shù)據(jù)更有效也更為靈活慎式。文件包括兩種類型:文本文件和二進制文件终佛。
二進制文件直接由比特0和比特1組成,沒有統(tǒng)一字符編碼翔忽,文件內(nèi)部數(shù)據(jù)的組織格式與文件用途有關(guān)英融。二進制文件和文本文件最主要的區(qū)別在于是否有統(tǒng)一的字符編碼
無論文件創(chuàng)建為文本文件或者二進制文件,都可以用“文本文件方式”和“二進制文件方式”打開歇式,打開后的操作不同驶悟。
#理解文本文件和二進制文件的區(qū)別
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'
采用文本方式讀入文件,文件經(jīng)過編碼形成字符串贬丛,打印出有含義的字符撩银;采用二進制方式打開文件,文件被解析為字節(jié)(byte)流豺憔。由于存在編碼额获,字符串中的一個字符由2個字節(jié)表示够庙。
文件的打開關(guān)閉
Python對文本文件和二進制文件采用統(tǒng)一的操作步驟,即“打開-操作-關(guān)閉”
Python通過解釋器內(nèi)置的open()函數(shù)打開一個文件抄邀,并實現(xiàn)該文件與一個程序變量的關(guān)聯(lián)耘眨,open()函數(shù)格式如下:
<變量名> = open(<文件名>, <打開模式>)
open()函數(shù)有兩個參數(shù):文件名和打開模式。文件名可以是文件的實際名字境肾,也可以是包含完整路徑的名字
open()函數(shù)有7中基本的打開模式
文件的讀寫
根據(jù)打開方式不同可以對文件進行相應(yīng)的讀寫操作剔难,Python提供4個常用的文件內(nèi)容讀取方法
#文本文件逐行打印
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
中國是個偉大的國家奥喻!
中國地大物博
中國有五千年的文明
如果程序需要逐行處理文件內(nèi)容偶宫,建議采用上述代碼格式:
fo = open(fname, "r")
for line in fo:
# 處理一行數(shù)據(jù)
fo.close()
Python提供3個與文件內(nèi)容寫入有關(guān)的方法
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庫可以完成圖像歸檔和圖像處理兩方面功能需求:
- 圖像歸檔:對圖像進行批處理、生成圖像預(yù)覽瞭空、圖像格式轉(zhuǎn)換等揪阿;
- 圖像處理:圖像基本處理、像素處理匙铡、顏色處理等图甜。
PIL庫Image類解析
在PIL中碍粥,任何一個圖像文件都可以用Image對象表示
要加載一個圖像文件鳖眼,最簡單的形式如下,之后所有操作對im起作用
from PIL import Image
im = Image.open("D:\\pycodes\\birdnest.jpg")
#GIF文件圖像提取
#對一個GIF格式動態(tài)文件嚼摩,提取其中各幀圖像钦讳,并保存為文件。
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("處理結(jié)束")
no more images in GIF file
處理結(jié)束
#圖像的顏色交換
#交換圖像中的顏色枕面≡缸洌可以通過分離RGB圖片的三個顏色通道實現(xiàn)顏色交換
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')
#操作圖像的每個像素點需要通過函數(shù)實現(xiàn),采用lambda函數(shù)和point()方法搭配使用
im = Image.open('f:/PythonCourse/birdnest.jpg') #打開鳥巢文件
r, g, b = im.split() #獲得RGB通道數(shù)據(jù)
newg = g.point(lambda i: i * 0.9) # 將G通道顏色值變?yōu)樵瓉淼?.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類提供了更高級的圖像增強需求,它提供調(diào)整色彩度枕荞、亮度柜候、對比度搞动、銳化等功能。
#圖像的對比度增強渣刷。
#增強圖像的對比度為初始的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')
圖像字符畫繪制
位圖圖片是由不同顏色像素點組成的規(guī)則分布,如果采用字符串代替像素辅柴,圖像就成為了字符畫箩溃。
定義一個字符集,將這個字符集替代圖像中的像素點碌嘀。
ascii_char =list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjf1234568795t/\|()1{}[]?-_+~<>i!;:,\"^`'.")
定義彩色向灰度的轉(zhuǎn)換公式如下涣旨,其中R、G股冗、B分別是像素點的RGB顏色值:
Gray = R * 0.2126 + G * 0.7152 + B * 0.0722
因此开泽,像素的RGB顏色值與字符集的對應(yīng)函數(shù)如下:
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()
一二維數(shù)據(jù)格式化和處理
數(shù)據(jù)組織的維度
一維數(shù)據(jù)由對等關(guān)系的有序或無序數(shù)據(jù)構(gòu)成,采用線性方式組織魁瞪,對應(yīng)于數(shù)學(xué)中的數(shù)組和集合等概念穆律。
二維數(shù)據(jù),也稱表格數(shù)據(jù)导俘,由關(guān)聯(lián)關(guān)系數(shù)據(jù)構(gòu)成峦耘,采用表格方式組織,對應(yīng)于數(shù)學(xué)中的矩陣旅薄,常見的表格都屬于二維數(shù)據(jù)辅髓。
高維數(shù)據(jù)由鍵值對類型的數(shù)據(jù)構(gòu)成,采用對象方式組織少梁,屬于整合度更好的數(shù)據(jù)組織方式洛口。高維數(shù)據(jù)在網(wǎng)絡(luò)系統(tǒng)中十分常用,HTML凯沪、XML第焰、JSON等都是高維數(shù)據(jù)組織的語法結(jié)構(gòu)
一二維數(shù)據(jù)的存儲格式
一維數(shù)據(jù)是最簡單的數(shù)據(jù)組織類型,有多種存儲格式妨马,常用特殊字符分隔:
(1)用一個或多個空格分隔挺举,例如:
中國 美國 日本 德國 法國 英國 意大利
(2)用逗號分隔,例如:
中國,美國,日本,德國,法國,英國,意大利
(3)用其他符號或符號組合分隔烘跺,建議采用不出現(xiàn)在數(shù)據(jù)中的特殊符號
中國; 美國; 日本; 德國; 法國; 英國; 意大利
逗號分割數(shù)值的存儲格式叫做CSV格式(Comma-Separated Values湘纵,即逗號分隔值),它是一種通用的滤淳、相對簡單的文件格式梧喷,在商業(yè)和科學(xué)上廣泛應(yīng)用,尤其應(yīng)用在程序之間轉(zhuǎn)移表格數(shù)據(jù)。
(1)純文本格式铺敌,通過單一編碼表示字符绊困;
(2)以行為單位,開頭不留空行适刀,行之間沒有空行秤朗;
(3)每行表示一個一維數(shù)據(jù),多行表示二維數(shù)據(jù)笔喉;
(4)以逗號分隔每列數(shù)據(jù)取视,列數(shù)據(jù)為空也要保留逗號;
(5)可以包含或不包含列名常挚,包含時列名放置在文件第一行作谭。
二維數(shù)據(jù)采用CSV存儲后的內(nèi)容如下:
城市,環(huán)比,同比,定基
北京,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工具打開奄毡,也可以在其他操作系統(tǒng)平臺上用文本編輯工具打開折欠。
一二維數(shù)據(jù)的表示和讀寫
CSV文件的每一行是一維數(shù)據(jù),可以使用Python中的列表類型表示吼过,整個CSV文件是一個二維數(shù)據(jù)锐秦,由表示每一行的列表類型作為元素,組成一個二維列表盗忱。
[
['城市', '環(huán)比', '同比', '定基'],
['北京', '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 = [
['城市', '環(huán)比', '同比', '定基'],
['北京', '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()
#導(dǎo)入CSV格式數(shù)據(jù)到列表
fo = open("f:/PythonCourse/price2016.csv", "r")
ls = []
for line in fo:
line = line.replace("\n","")
ls.append(line.split(","))
print(ls)
fo.close()
[['城市', '環(huán)比', '同比', '定基'], ['北京', '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èi)容時,每行最后一個元素后面包含了一個換行符("\n")趟佃。對于數(shù)據(jù)的表達和使用來說扇谣,這個換行符是多余的,可以通過使用字符串的replace()方法將其去掉闲昭,如第4行罐寨。
#逐行處理CSV格式數(shù)據(jù)。
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()
城市 環(huán)比 同比 定基
北京 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
#一維數(shù)據(jù)寫入CSV文件
fo = open("f:/PythonCourse/price2016bj.csv", "w")
ls = ['北京', '101.5', '120.7', '121.4']
fo.write(",".join(ls)+ "\n")
fo.close()
對于列表中存儲的二維數(shù)據(jù)序矩,可以通過循環(huán)寫入一維數(shù)據(jù)的方式寫入CSV文件鸯绿,參考代碼樣式如下:
for row in ls:
<輸出文件>.write(",".join(row)+"\n")
#二維數(shù)據(jù)寫入CSV文件
fr = open("f:/PythonCourse/price2016.csv", "r")
fw = open("f:/PythonCourse/price2016out.csv", "w")
ls = []
for line in fr: #將CSV文件中的二維數(shù)據(jù)讀入到列表變量
line = line.replace("\n","")
ls.append(line.split(","))
for i in range(len(ls)): #遍歷列表變量計算百分?jǐn)?shù)
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: #將列表變量中的二位數(shù)據(jù)輸出到CSV文件
print(row)
fw.write(",".join(row)+"\n")
fr.close()
fw.close()
['城市', '環(huán)比', '同比', '定基']
['北京', '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展示
展示二位數(shù)據(jù)的對應(yīng)的HTML代碼:
<!DOCTYPE HTML>
<html>
<body>
<meta charset=utf-8>
<h2 align=center>2016年7月部分大中城市新建住宅價格指數(shù)</h2>
<table border='1' align=center width=70%>
<tr bgcolor='orange'>
<th width="25%">城市</th>
<th width="25%">環(huán)比</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月部分大中城市新建住宅價格指數(shù)</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()
[['城市', '環(huán)比', '同比', '定基'], ['北京', '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']]
高維數(shù)據(jù)的格式化
與一維二維數(shù)據(jù)不同,高維數(shù)據(jù)能展示數(shù)據(jù)間更為復(fù)雜的組織關(guān)系贮泞。為了保持靈活性楞慈,表示高維數(shù)據(jù)不采用任何結(jié)構(gòu)形式幔烛,僅采用最基本的二元關(guān)系啃擦,即鍵值對。萬維網(wǎng)是高維數(shù)據(jù)最成功的典型應(yīng)用饿悬。
JSON格式可以對高維數(shù)據(jù)進行表達和存儲令蛉。JSON(JavaScript Object Notation)是一種輕量級的數(shù)據(jù)交換格式,易于閱讀和理解。JSON格式表達鍵值對基本格式如下珠叔,鍵值對都保存在雙引號中:
"key" : "value"
當(dāng)多個鍵值對放在一起時蝎宇,JSON有如下一些約定:
- 數(shù)據(jù)保存在鍵值對中;
- 鍵值對之間由逗號分隔祷安;
- 括號用于保存鍵值對數(shù)據(jù)組成的對象姥芥;
- 方括號用于保存鍵值對數(shù)據(jù)組成的數(shù)組。
"本書作者" : [
{ "姓氏" : "嵩",
"名字" : "天",
"單位" : "北京理工大學(xué)" },
{ "姓氏" : "禮",
"名字" : "欣",
"單位" : "北京理工大學(xué)" },
{ "姓氏" : "黃",
"名字" : "天羽",
"單位" : "北京理工大學(xué)" }
]
json庫的使用
Json庫的概述
json庫主要包括兩類函數(shù):操作類函數(shù)和解析類函數(shù)
- 操作類函數(shù)主要完成外部JSON格式和程序內(nèi)部數(shù)據(jù)類型之間的轉(zhuǎn)換功能
- 解析類函數(shù)主要用于解析鍵值對內(nèi)容汇鞭。
Json庫的解析
dumps()和loads()分別對應(yīng)編碼和解碼功能凉唐。
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格式相互轉(zhuǎn)換
CSV格式常用于一二維數(shù)據(jù)表示和存儲,JSON也可以表示一二維數(shù)據(jù)霍骄。在網(wǎng)絡(luò)信息傳輸中台囱,可能需要統(tǒng)一表示方式,因此读整,需要在CSV和JSON格式間進行相互轉(zhuǎn)換簿训。
#將CSV轉(zhuǎn)換成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格式數(shù)據(jù)轉(zhuǎn)換成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()