我們將在本章介紹以下案例:
- 從分隔符文本文件中讀取數(shù)據(jù)
- 發(fā)送電子郵件
- 訪問FTP服務(wù)器中的文件
- 創(chuàng)建ZIP文件
- 讀取XML文件
引言
在本章中,你將學(xué)習(xí)如何編寫Python腳本來執(zhí)行常用的處理任務(wù)线婚。這些任務(wù)包括讀寫分隔符文本文件嚼沿,發(fā)送電子郵件瞳腌,與FTP服務(wù)器交互操作,創(chuàng)建.zip文件以及讀寫JSON和XML文件嫉柴。GIS程序員應(yīng)當(dāng)了解如何在Python腳本來完成這些功能备畦。
從分隔符文本文件中讀取數(shù)據(jù)
對于GIS程序員來說使用Python處理文件是非常重要的環(huán)節(jié)。文本文件經(jīng)常作為不同系統(tǒng)之間的數(shù)據(jù)交換格式渴频。文本文件簡單,跨平臺并且易于處理北启。逗號分隔符文本文件和制表符分隔符文本文件是最為常用的形式卜朗。對于GIS程序員來說讀取包含X,Y坐標(biāo)以及其他屬性信息的逗號分隔符文本文件是一類常見的處理任務(wù)咕村。這些讀取后信息再轉(zhuǎn)換成像shapefile或地理數(shù)據(jù)庫的GIS數(shù)據(jù)格式场钉。
Getting ready
使用Python的文件處理功能前,你必須首先打開文件懈涛。文件打開后逛万,文件中的數(shù)據(jù)就可以通過Python提供的功能進行處理,最后關(guān)閉文件批钠。處理完成后要記得關(guān)閉文件宇植。
在本案例中,你將學(xué)習(xí)如何對一個逗號分隔符文本文件執(zhí)行打開价匠,讀取,處理并關(guān)閉操作呛每。
How to do it...
按照以下步驟創(chuàng)建Python腳本來讀取逗號分隔符文本文件:
1.在C:\ArcpyBook\data文件夾中找到一個N_America.A2007275.txt的文件踩窖。用文本編輯器打開該文件,你會看到如下內(nèi)容:
18.102,-94.353,310.7,1.3,1.1,10/02/2007,0420,T,72
19.300,-89.925,313.6,1.1,1.0,10/02/2007,0420,T,82
19.310,-89.927,309.9,1.1,1.0,10/02/2007,0420,T,68
26.888,-101.421,307.3,2.7,1.6,10/02/2007,0425,T,53
26.879,-101.425,306.4,2.7,1.6,10/02/2007,0425,T,45
36.915,-97.132,342.4,1.0,1.0,10/02/2007,0425,T,100
................
該文件包含的火情數(shù)據(jù)是從2007年10月02日當(dāng)天衛(wèi)星遙感影像判斷獲取晨横。每行數(shù)據(jù)包含了經(jīng)緯度信息以及其他相關(guān)信息洋腮,比如日期和時間箫柳,衛(wèi)星類型,可信度等等啥供。在本案例中悯恍,你將提取出緯度,經(jīng)度和可信度信息伙狐。
2.打開IDLE涮毫,創(chuàng)建一個腳本文件并保存為
C:\ArcpyBook\Appendix2\ReadDelimitedTextFile.py
文件。
3.調(diào)用Pyhon的open()
函數(shù)來打開要讀取的文件:
f = open("C:/ArcpyBook/data/N_America.A2007275.txt","r")
4.讀取文本文件中的內(nèi)容并寫入到列表中:
lstFires = f.readlines()
5.添加一個for
循環(huán)語句來迭代遍歷lstFires
變量中的所有行:
for fire in lstFires:
6.調(diào)用split()
函數(shù)并使用逗號作為分隔符贷屎,將分離后的值保存到列表中罢防,然后賦值給變量lstValues
。保證語句的縮進使其位于for
語句中:
lstValues = fire.split(",")
7.使用索引值來獲取緯度唉侄,經(jīng)度和可信度咒吐,并分別創(chuàng)建新的變量:
latitude = float(lstValues[0])
longitude = float(lstValues[1])
confid = int(lstValues[8])
8.使用print
語句打印所有值:
print "The latitude is: " + str(latitude) + " The longtitude is " + str(longtitude) + "The confidence value is " + str(confid)
9.關(guān)閉文件:
f.close()
10.完整代碼如下:
f = open("C:/ArcpyBook/data/N_America.A2007275.txt","r")
lstFires = f.readlines()
for fire in lstFires:
lstValues = fire.split(",")
latitude = float(lstValues[0])
longitude = float(lstValues[1])
confid = int(lstValues[8])
print "The latitude is: " + str(latitude) + " The longtitude is " + str(longtitude) + "The confidence value is " + str(confid)
f.close()
11.保存并運行腳本。你將看到如下結(jié)果顯示:
The latitude is: 18.102 The longitude is: -94.353 The confidence value is: 72
The latitude is: 19.3 The longitude is: -89.925 The confidence value is: 82
The latitude is: 19.31 The longitude is: -89.927 The confidence value is: 68
The latitude is: 26.888 The longitude is: -101.421 The confidence value is: 53
The latitude is: 26.879 The longitude is: -101.425 The confidence value is: 45
The latitude is: 36.915 The longitude is: -97.132 The confidence value is: 100
...................
The latitude is: 54.19 The longitude is: -122.502 The confidence value is: 92
How it works...
Python中open()
函數(shù)創(chuàng)建一個文件對象属划,該對象引用一個鏈接地址來指向計算機中的文件恬叹。open()
函數(shù)中的第一個參數(shù)是你想要打開文件的路徑。第二個參數(shù)指定一種模式同眯,該模式通常是只讀(r
)绽昼,寫入(w
)或添加(a
)。r
模式表明你打開文件進行只讀操作嗽测,而w
模式則表明你打開文件要進行寫入操作绪励。如果你以寫入模式打開的文件已存在,那么Python就會覆蓋掉該文件中已有數(shù)據(jù)唠粥,因此使用該模式應(yīng)當(dāng)注意疏魏。添加模式(a
)則會打開文件進行寫入操作,但是不會覆蓋已有數(shù)據(jù)晤愧,而是在文件末尾添加寫入的數(shù)據(jù)大莫。在本案例中,我們以只讀模式打開N_America.A2007275.txt
文件官份。
readlines()
函數(shù)會讀取整個文件內(nèi)容并寫入一個Python列表中只厘。該列表保存到變量lstFires
。文本文件中的每一行數(shù)據(jù)是列表中的一個元素舅巷。由于該函數(shù)會讀取整個文件到列表中羔味,因此調(diào)用該方法時需要注意,一個大文件會顯著影響性能钠右。
for
循環(huán)語句用于迭代遍歷lstFires
中的每一個值赋元,在該語句中的split()
函數(shù)用于從以某種分隔符分隔文本行中創(chuàng)建一個列表對象。本案例中的文件是以逗號作為分隔符,因此我們可以調(diào)用split(",")
語句搁凸。你還可以使用其他像制表符媚值,空格或其他分隔符來分割文本。split()
函數(shù)創(chuàng)建的列表對象保存在lstValues
變量中护糖。該變量包含了每一個火情數(shù)據(jù)褥芒。如下圖所示。你會看到緯度數(shù)據(jù)占據(jù)第一個位置嫡良,經(jīng)度數(shù)據(jù)占據(jù)第二個數(shù)據(jù)锰扶。列表從零值開始索引:
使用索引值(分別引用緯度,經(jīng)度和可信度)皆刺,我們創(chuàng)建了latitude
少辣,longitude
以及confid
三個新變量。最后羡蛾,我們打印輸出每一個值漓帅。我們可以調(diào)用插入游標(biāo)(InsertCursor
)對象將這些信息寫入到一個要素類中。
There's more...
同讀取文件一樣痴怨,你還可以向文件中寫入數(shù)據(jù)忙干。write()
函數(shù)可用于將列表結(jié)構(gòu)的內(nèi)容寫入到一個文件中。寫入數(shù)據(jù)之前浪藻,你需要先以寫入或添加模式打開文件捐迫。
發(fā)送電子郵件
有時候,你可能需要編寫Python腳本來發(fā)送電子郵件爱葵。舉個例子施戴,在一個長時間運行的地理處理操作中需要提醒操作成功完成或出現(xiàn)錯誤,在類似情況下萌丈,發(fā)送電子郵件就很有用處赞哗。
Getting ready
通過Python腳本發(fā)送電子郵件需要腳本運行的機器能夠訪問郵箱服務(wù)器,可以是一個Yahoo辆雾,Gmail之類的公共的電子郵件服務(wù)肪笋,這也可以使用像Outlook的應(yīng)用程序配置的發(fā)送郵件服務(wù)器。不論哪種方式度迂,你都需要知道電子郵箱服務(wù)器的域名和端口藤乙。Python的smtplib模塊用于創(chuàng)建郵箱服務(wù)器的連接并發(fā)送電子郵件。
Python的email
模塊包含一個Message
類用來表達電子郵件信息惭墓。每一條消息包含消息頭和消息體坛梁。該類不能用于發(fā)送電子郵件,只是處理消息對象的表達腊凶。Message
類通過調(diào)用message_from_file()
和message_from_string()
函數(shù)分別解析包含在電子郵件中的文件和字符串划咐。兩個函數(shù)都會創(chuàng)建一個新的Message
對象毅人。郵件體可以通過調(diào)用Message.get_payload()
方法獲取。
在本案例中尖殃,你將學(xué)習(xí)如何在Python腳本中使用smtp
類來發(fā)送包含附件內(nèi)容的電子郵件。
原書采用Gmail郵箱服務(wù)划煮,由于網(wǎng)絡(luò)原因送丰,我們在案例中改為使用網(wǎng)易126郵箱服務(wù)。如果你已經(jīng)擁有了一個126賬號弛秋,那么只要提供你的用戶名和密碼就可以器躏。如果你還沒有126賬號,你需要注冊一個或者使用其他郵件服務(wù)來完成本練習(xí)蟹略;126郵箱賬號是免費的登失。
How to do it...
按照以下步驟來創(chuàng)建能夠發(fā)送電子郵件的腳本:
1.打開IDLE,創(chuàng)建一個腳本并保存為C:\ArcpyBook\Appendix2\SendEmail.py
挖炬。
2.為了能夠在發(fā)送帶附件的電子郵件揽浙,你需要導(dǎo)入os
模塊,smtplib
模塊以及email
模塊中多個類意敛。如下所示:
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email import Encoders
import os
3.創(chuàng)建下面的幾個變量并分別保存你的Gmail用戶名和密碼馅巷。
##<用戶名>替換為你的郵箱賬號
gmail_user = "<用戶名>"
##<密碼>替換為你的郵箱賬號密碼
gmail_pwd= "<密碼>"
4.定義一個mail()
函數(shù)。該函數(shù)將接受四個參數(shù):to
草姻,subject
钓猬,text
以及attach
。每一個參數(shù)的意義不言而喻撩独。創(chuàng)建一個新的MIMEMultipart
對象并分別賦值給from
敞曹,to
和subject
鍵值。你還可以對新創(chuàng)建的對象調(diào)用MIMEMultipart.attach()
方法來給郵件添加一個文本附件:
def mail(to,subject,text,attach):
msg = MIMEMultipart()
msg['From'] = gmail_user
msg['To'] = to
msg['Subject'] = subject
msg.attach(MIMEText(text))
5.在郵件中添加附件:
part = MIMEBase("application","octet-stream")
part.set_payload(open(attach,"rb").read())
Encoders.encode_base64(part)
part.add_header("Content-Dispositon","attachment;filename='%s'" % os.path.basename(attach))
msg.attach(part)
6.創(chuàng)建一個新的SMTP
對象引用谷歌Gamil服務(wù)综膀,傳遞用戶名和密碼來連接該郵件服務(wù)澳迫,發(fā)送郵件最后關(guān)閉連接:
mailServer = smtplib.SMTP("smtp.126.com")
mailServer.ehlo()
mailServer.starttls()
mailServer.ehlo()
mailServer.login(gmail_user,gmail_pwd)
mailServer.sendmail(gmail_user,to,msg.as_string())
mailServer.quit()
7.調(diào)用mail()
函數(shù),傳遞收件人僧须,郵件主題纲刀,郵件的內(nèi)容以及附件參數(shù):
##<收件人地址>替換為發(fā)件人郵箱地址
mail("<收件人地址>","Hello from python!","This is an email sent with python","C:/ArcpyBook/data/bc_pop1996.csv")
8.完整代碼如下:
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email import Encoders
import os
##<用戶名>替換為你的郵箱賬號
gmail_user = "<用戶名>"
##<密碼>替換為你的郵箱賬號密碼
gmail_pwd= "<密碼>"
def mail(to,subject,text,attach):
msg = MIMEMultipart()
msg['From'] = gmail_user
msg['To'] = to
msg['Subject'] = subject
msg.attach(MIMEText(text))
part = MIMEBase("application","octet-stream")
part.set_payload(open(attach,"rb").read())
Encoders.encode_base64(part)
part.add_header("Content-Disposition","attachment;filename='%s'" % os.path.basename(attach))
msg.attach(part)
mailServer = smtplib.SMTP("smtp.126.com")
mailServer.ehlo()
mailServer.starttls()
mailServer.ehlo()
mailServer.login(gmail_user,gmail_pwd)
mailServer.sendmail(gmail_user,to,msg.as_string())
mailServer.quit()
print "Send Successfully!"
##<收件人地址>替換為發(fā)件人郵箱地址
mail("<收件人地址>","Hello from python!","This is an email sent with python","C:/ArcpyBook/data/bc_pop1996.csv")
9.保存并運行腳本。指定某個郵箱賬號作為收件人担平。
How it works...
mail()
函數(shù)接受的第一個參數(shù)是接收郵件的電子郵箱地址示绊。該地址可以是任何合法的電子郵箱地址,不過需要提供一個可以查看的郵箱賬號暂论,這樣你才可以確認腳本是否正確執(zhí)行面褐。第二個參數(shù)是郵件的主題。第三個參數(shù)是郵件內(nèi)容取胎。最后一個參數(shù)是附件的名稱展哭。在這里將bc_pop1996.csv
文件作為附件湃窍。你還可以使用任何你能夠獲取的文件。
隨后我們在mail()
函數(shù)中創(chuàng)建了一個新的MIMEMultipart
對象匪傍,并分別賦給from
您市,to
和subject
鍵值。你還可以調(diào)用MIMEMultipart.attach()
方法將郵件內(nèi)容附加到msg
對象中役衡。隨后通過調(diào)用msg.attach(part)
語句將bc_pop1996.csv
文件作為附件添加到使用MIMEBase
對象創(chuàng)建的郵件中茵休。
到目前為止,我們已經(jīng)了解了如何發(fā)送一個簡單的電子郵件手蝎。但是榕莺,我們需要發(fā)送一個包含文本和附件的更為復(fù)雜的電子郵件。這就需要使用MIME消息棵介,該消息提供處理多用途電子郵件的功能钉鸯。MIME消息需要不同部分的邊界以及額外的頭信息來指定要發(fā)送的內(nèi)容。MIMEBase
類是一個Message
的抽象子類并且能夠發(fā)送多部分類型的郵件邮辽。由于這是一個抽象子類唠雕,因此你不能創(chuàng)建真正意義的實例。不過你可以使用其中的一個子類吨述,比如MIMEText
來實現(xiàn)及塘。mail()
函數(shù)中的最后一步創(chuàng)建一個新的SMTP
對象來指向126郵件服務(wù),傳遞用戶名和密碼來連接該郵件服務(wù)锐极,發(fā)送郵件最后關(guān)閉連接笙僚。
訪問FTP服務(wù)器中的文件
對于GIS程序員來說獲取FTP服務(wù)器中的文件進行處理也是非常普遍的操作,并且這類操作頁可以利用Python腳本來實現(xiàn)自動化處理灵再。
Getting ready
通過ftplib
模塊可以完成連接FTP服務(wù)器并下載文件操作肋层。FTP
對象接受一個主機名稱,一個用戶名以及密碼參數(shù)來創(chuàng)建一個與FTP服務(wù)器的連接翎迁。連接打開之后栋猖,你就可以查找并下載文件了。
在本案例中汪榔,你將連接到NASA的某FTP站點下載一副TIF格式的圖像蒲拉。
How to do it...
按照以下步驟創(chuàng)建腳本來連接到一個FTP服務(wù)器并下載文件:
1.打開IDLE,創(chuàng)建一個腳本并保存為C:\ArcpyBook\Appendix2\ftp.py
痴腌。
2.我們將要連接到NASA的FTP服務(wù)器雌团。訪問網(wǎng)站ftp://is.sci.gsfc.nasa.gov。
3.導(dǎo)入ftplib
士聪,os
和socket
模塊:
import ftplib
import os
import socket
4.添加以下變量分別定義URL地址锦援,目錄和文件名:
HOST = "is.sci.gsfc.nasa.gov"
DIRN= "/testdata/BLUEMARBLE_POSTER_IMAGES/"
FILE = "FLOOD_VNCLR_d20140601_t0612599_e0614240_BEFORE.tif"
5.添加以下語句塊創(chuàng)建一個連接。如果連接出現(xiàn)錯誤會生成一條錯誤消息剥悟。如果連接成功則會顯示一條成功連接的消息:
try:
f = ftplib.FTP(HOST)
except (socket.error,socket.gaierror),e:
print "ERROR: cannot reach '%s'" % HOST
print "*** Connected to host '%s'" % HOST
6.添加以下語句塊來匿名方式登錄服務(wù)器:
try:
f.login()
except ftplib.error_perm:
print "ERROR: cannot login anonymously"
f.quit()
print "*** Logged in as 'anonymous'"
7.添加以下語句塊將當(dāng)期目錄更新至DIRN變量中指定的目錄:
try:
f.cwd(DIRN)
except ftplib.error_perm:
print "ERROR: cannot CD to '%s'" % DIRN
f.quit()
print "*** Changed to '%s'" % DIRN
8.調(diào)用FTP.retrbinary()
函數(shù)獲取數(shù)據(jù)文件:
try:
f.retrbinary("RETR %s" %FILE,open(FILE,'wb').write)
except ftplib.error_perm:
print "ERROR: cannot read file '%s'" % FILE
os.unlink(FILE)
else:
print "*** Downloaded '%s' to CWD" % FILE
9.斷開與服務(wù)器的連接:
f.quit()
10.完整代碼如下:
import ftplib
import os
import socket
HOST = "is.sci.gsfc.nasa.gov"
DIRN= "/testdata/BLUEMARBLE_POSTER_IMAGES/"
FILE = "FLOOD_VNCLR_d20140601_t0612599_e0614240_BEFORE.tif"
try:
f = ftplib.FTP(HOST)
print "*** Connected to host '%s'" % HOST
try:
f.login()
print "*** Logged in as 'anonymous'"
try:
f.cwd(DIRN)
print "*** Changed to '%s'" % DIRN
try:
f.retrbinary("RETR %s" %FILE,open(FILE,'wb').write)
except ftplib.error_perm:
print "ERROR: cannot read file '%s'" % FILE
os.unlink(FILE)
else:
print "*** Downloaded '%s' to CWD" % FILE
finally:
f.quit()
except ftplib.error_perm:
print "ERROR: cannot CD to '%s'" % DIRN
f.quit()
except ftplib.error_perm:
print "ERROR: cannot login anonymously"
f.quit()
except (socket.error,socket.gaierror),e:
print "ERROR: cannot reach '%s'" % HOST
11.保存并運行腳本灵寺。如果一切順利的話曼库,你會看到如下結(jié)果顯示:
*** Connected to host 'is.sci.gsfc.nasa.gov'
*** Logged in as 'anonymous'
*** Changed to '/testdata/BLUEMARBLE_POSTER_IMAGES/'
*** Downloaded 'FLOOD_VNCLR_d20140601_t0612599_e0614240_BEFORE.tif' to CWD
12.查看C:\ArcpyBook\Appendix2
目錄下的文件。默認情況下略板,F(xiàn)TP會將文件下載到當(dāng)前工作目錄中(同python腳本文件位于同一目錄下):
How it works...
連接FTP服務(wù)器之前毁枯,你需要先知道URL地址。你還需要知道要下載文件的文件名和所在目錄叮称。在腳本中后众,我們已經(jīng)對這些信息進行硬編碼處理,這樣你就可以專注于應(yīng)用FTP相關(guān)的功能颅拦。利用這些信息我們隨后會創(chuàng)建一個NASA的FTP服務(wù)器的連接。這可以通過ftplib.FTP()
函數(shù)接受一個URL地址作為主機參數(shù)來完成教藻。
is.sci.gsfc.nasa.gov
服務(wù)器接受匿名登錄距帅,因此我們采用這樣方式來連接服務(wù)器。需要注意一點括堤,如果服務(wù)器不接受匿名登錄方式碌秸,你就需要提供一個用戶名和密碼。登錄成功后悄窃,隨后會將當(dāng)前的根目錄地址更改為DIRN
變量中定義的目錄讥电。這一步通過調(diào)用cwd(<path>)
函數(shù)來實現(xiàn)。隨后調(diào)用retrbinary()
函數(shù)來下載kmz文件轧抗。最后恩敌,你還需要在下載完成后斷開與FTP服務(wù)器的連接。這一步可通過調(diào)用quit()
方法完成横媚。
There's more...
你還可以調(diào)用其他與FTP相關(guān)的方法來執(zhí)行不同的操作纠炮。通常來講,這些方法可分為目錄級別操作與文件級別操作灯蝴。目錄級別方法包括dir()
方法用來獲取目錄中的文件列表恢口,mkd()
方法用來創(chuàng)建一個新的目錄,pwd()
方法來獲取當(dāng)前的工作目錄穷躁,而cwd()
方法則更改當(dāng)前目錄位置耕肩。
ftplib
模塊還包括與文件操作相關(guān)的方法。你可以上傳或下載二進制文件或純文本文件问潭。retrbinary()
和storbinary()
方法則分別用于獲取和保存文件猿诸。純文本文件可以調(diào)用retrlines()
和storlines()
方法來獲取和保存。
你還可以關(guān)注FTP類中的其他方法狡忙。調(diào)用delete()
方法可以刪除文件两芳,而rename()
方法可以重命名文件。你還可以通過調(diào)用sendcmd()
方法來向FTP服務(wù)器發(fā)送指令去枷。
創(chuàng)建ZIP文件
GIS日常業(yè)務(wù)中需要將大文件壓縮為.zip格式便于共享怖辆。你可以使用Python提供的模塊來解壓縮.zip格式文件是复。
Getting ready
Zip格式是一種常用的壓縮歸檔格式,該格式可以使用Python中的zipfile
模塊進行處理竖螃。ZipFile
類可用于創(chuàng)建淑廊,讀取以及寫入.zip
文件。創(chuàng)建一個新的.zip
文件特咆,你只要提供一個文件名以及模式參數(shù)季惩,比如w
模式則表明你想要對文件寫入數(shù)據(jù)。下面的代碼示例中腻格,我們創(chuàng)建一個叫做dataFile.zip
的文件画拾。第二個參數(shù)w
表示會創(chuàng)建一個新文件。在寫入模式中會創(chuàng)建一個新文件或覆蓋帶相同名稱的已有文件菜职。一個可選的壓縮參數(shù)可在創(chuàng)建文件時使用青抛。該參數(shù)可以設(shè)置為ZIP_STORED
或者ZIP_DEFLATED
:
zipfile.ZipFile("dataFile.zip","w","ZIP_STORED")
在本案例中,你會將位于C:\ArcpyBook\data
目錄下的所有shapefile文件打包壓縮成一個zip
格式的壓縮文件酬核。
How to do it...
按照以下步驟來學(xué)習(xí)如何編寫腳本來創(chuàng)建一個.zip文件:
1.打開IDLE蜜另,創(chuàng)建一個腳本文件并保存為C:\ArcpyBook\Appendix2\CreateZipfile.py
。
2.導(dǎo)入zipfile
和os
模塊:
import zipfile
import os
3.以寫入模式創(chuàng)建一個新的shapefile.zip
文件嫡意,并添加一個壓縮參數(shù):
zfile = zipfile.ZipFile("shapefile.zip","w",zipfile.ZIP_STORED)
4.下一步举瑰,我們會調(diào)用os.listdir()
函數(shù)來創(chuàng)建數(shù)據(jù)目錄中的文件列表:
files = os.listdir("C:/ArcpyBook/data")
5.循環(huán)遍歷了列表中的文件,如果文件擴展名為shp
蔬螟,shx
或dbf
則寫入.zip
文件中:
for f in files:
if f.endswith("shp") or f.endswith("shx") or f.endswith("dbf"):
zfile.write("C:/ArcpyBook/data/" + f)
6.打印文件列表中所有寫入到zip
文件中的文件此迅。你可以調(diào)用ZipFile.namelist()
函數(shù)來創(chuàng)建壓縮文件中的文件列表:
for f in zipfile.namelist():
print "Added %s" % f
7.關(guān)閉.zip
文件:
zfile.close()
8.完整代碼如下;
import zipfile
import os
zfile = zipfile.ZipFile("shapefile.zip","w",zipfile.ZIP_STORED)
files = os.listdir("C:/ArcpyBook/data")
for f in files:
if f.endwith("shp") or f.endwith("shx") or f.endwith("dbf"):
zfile.write("C:/ArcpyBook/data/" + f)
for f in zfile.namelist():
print "Added %s" % f
zfile.close()
9.保存并運行代碼。你會看到如下結(jié)果顯示:
Added ArcpyBook/data/Burglaries_2009.dbf
Added ArcpyBook/data/Burglaries_2009.shp
Added ArcpyBook/data/Burglaries_2009.shx
Added ArcpyBook/data/Streams.dbf
Added ArcpyBook/data/Streams.shp
Added ArcpyBook/data/Streams.shx
10.在資源管理器中旧巾,你可以看到如下圖所示的.zip
文件邮屁。注意壓縮文件的大小(文件大小視文件夾中滿足條件的文件決定),該文件沒有進行壓縮:
11.現(xiàn)在我們要創(chuàng)建一個壓縮版本的.zip
文件看一看有什么變化菠齿。如下所示修改代碼:
zfile = zipfile.ZipFile("shapefile2.zip","w",zipfile.ZIP_DEFLATED)
12.保存后運行腳本佑吝。
13.查看你剛才創(chuàng)建的shapefile2.zip文件的大小。壓縮后文件變小了:
How it works...
在本案例中绳匀,我們以寫入模式創(chuàng)建了一個叫做shapefile.zip
的文件芋忿。在第一版腳本中,我們沒有壓縮文件內(nèi)容疾棵。第二個版本中我們在ZipFile
對象構(gòu)造函數(shù)中使用了DEFLATED
參數(shù)來實現(xiàn)文件內(nèi)容的壓縮戈钢。隨后腳本獲取數(shù)據(jù)目錄中的文件列表并循環(huán)遍歷每一個文件。隨后通過調(diào)用write()
函數(shù)將擴展名為.shp
是尔,.shx
或.dbf
的文件寫入到壓縮文件中殉了。最后,壓縮文件中的所有文件名打印輸出到屏幕中拟枚。
There's more...
保存在ZIP壓縮文件中的內(nèi)容可以通過調(diào)用read()
方法來進行讀取薪铜。首先文件以讀取模式打開众弓,隨后調(diào)用read()
方法并接受一個表示需要讀取的文件名參數(shù)。文件內(nèi)容之后既可以選擇打印輸出到屏幕上隔箍,也可以寫入到其他文件中或保存為列表或字典變量中谓娃。舉個例子,readme.zip
壓縮文件中包含一個readme.txt
文件蜒滩,下面的腳本代碼就可以實現(xiàn)讀取readme.txt
文件文本內(nèi)容的功能:
import zipfile
zipFile=zipfile.ZipFile("readme.zip","r")
fcontent=zipFile.read("readme.txt")
print fcontent
zipFile.close()
讀取XML文件
XML文件是一種傳輸數(shù)據(jù)和保存數(shù)據(jù)的格式滨达。由于數(shù)據(jù)是保存在純文本文件中,因此XML文件是不依賴平臺的俯艰。結(jié)構(gòu)上類似于HTML捡遍,不過HTML用于顯示數(shù)據(jù)而XML則是用于數(shù)據(jù)傳輸。XML文件有時候會作為不同軟件系統(tǒng)之間的GIS數(shù)據(jù)交換格式竹握。
Getting ready
XML文檔是一個樹形結(jié)構(gòu)画株,由根元素,子元素以及元素屬性構(gòu)成涩搓。元素通常稱作節(jié)點(Node)。所有的XML文件都包含一個根元素劈猪。根元素是所有其他元素或子節(jié)點的父元素昧甘。下面的示例代碼則展示了一個XML文檔結(jié)構(gòu)。不同于HTML文件战得,XML文件大小寫敏感:
<root>
<child att="value">
<subchild>....</subchild>
</child>
</root>
Python提供了多個用于處理XML文件的模塊充边。具體使用哪個模塊應(yīng)該由所執(zhí)行的操作來決定。不要試圖使用單個模塊來解決所有問題常侦。每一個模塊都有自己擅長處理的特定功能浇冰。在本案例中,你會學(xué)習(xí)如何使用文檔中的nodes
和element
屬性來讀取XML文件中的數(shù)據(jù)聋亡。
你可以使用許多方法來訪問XML文檔中的節(jié)點屬性肘习。查找節(jié)點的標(biāo)簽名稱可能是最簡單的方式,然后遍歷包含子節(jié)點列表的目錄樹坡倔。在進行以上操作之前漂佩,你需要調(diào)用minidom.parse()
方法來解析XML文檔。解析文檔后罪塔,你就可以使用childNodes
屬性獲取一個包含了從根元素開始的所有子節(jié)點的列表投蝉。最后調(diào)用getElementsByTagName(tag)
函數(shù)來根據(jù)標(biāo)簽名稱查找節(jié)點。該函數(shù)會返回一個與tag
有關(guān)的所有子節(jié)點列表征堪。
你還可以通過調(diào)用hasAttribute(name)
方法來查看節(jié)點是否包含某個屬性名稱瘩缆,該函數(shù)返回一個布爾值。確定屬性存在后調(diào)用getAttribute(name)
方法獲取該屬性值佃蚜。
在本案例中將解析一個XML文件并提取出與某個特定元素(節(jié)點)和屬性有關(guān)的值庸娱。在該文件中着绊,我們會從所有的節(jié)點中查找<fire>
節(jié)點和address
屬性,查找到的address屬性值會打印到屏幕上涌韩。
How to do it...
1.打開IDLE畔柔,創(chuàng)建一個腳本并保存為
C:\ArcpyBook\Appendix2\XMLAccessElementAttribute.py
。
2.我們以位于C:\ArcpyBook\Appendix2
文件夾中的WitchFireResidenceDestroyed.xml
文件為例臣樱。下面是該文件的部分內(nèi)容:
<fires>
<fire address="11389 Pajaro Way" city="San Diego"
state="CA" zip="92127" country="USA" latitude="33.037187" longitude="-117.082299" />
<fire address="18157 Valladares Dr" city="San Diego" state="CA" zip="92127" country="USA" latitude="33.039406" longitude="-117.076344" />
<fire address="11691 Agreste Pl" city="San Diego" state="CA" zip="92127" country="USA" latitude="33.036575" longitude="-117.077702" />
<fire address="18055 Polvera Way" city="San Diego" state="CA" zip="92128" country="USA" latitude="33.044726" longitude="-117.057649" />
</fires>
3.從xml.dom
模塊中導(dǎo)入minidom
:
from xml.dom import minidom
4.解析XML文件:
xmldoc = minidom.parse("WitchFireResidenceDestroyed.xml")
5.創(chuàng)建XML文件中的節(jié)點列表:
childNodes = xmldoc.childNodes
6.生成一個包含所有<fire>
節(jié)點的列表:
eList = childNodes[0].getElementsByTagName("fire")
7.循環(huán)遍歷列表中的元素靶擦,檢測是否存在address
屬性。如果存在該屬性則打印該屬性值:
for e in eList:
if e.hasAttribute("address"):
print e.getAttribute("address")
8.保存并運行腳本雇毫。你會看到如下結(jié)果顯示:
11389 Pajaro Way
18157 Valladares Dr
11691 Agreste Pl
18055 Polvera Way
18829 Bernardo Trails Dr
18189 Chretien Ct
17837 Corazon Pl
18187 Valladares Dr
18658 Locksley St
18560 Lancashire Way
........
18682 Lancashire Way
18344 Lincolnshire St
How it works...
在腳本中加載XML文檔是處理XML文件最為基礎(chǔ)的事情玄捕,你可以使用xml.dom
模塊中minidom
對象來完成。minidom
對象包含的parse()
方法可接受一個xml文檔路徑并創(chuàng)建xml文件的文檔對象模型(DOM)樹對象棚放。
DOM樹中的childNodes
屬性生成一個包含XML文件中所有節(jié)點的列表枚粘。隨后可以調(diào)用getElementsByTagName()
方法來訪問這些節(jié)點。最后一步就是循環(huán)遍歷包含在eList
變量中的所有<fire>
節(jié)點飘蚯。對于每一個節(jié)點馍迄,調(diào)用hasAttribute()
方法來檢測是否包含address
屬性,如果存在則調(diào)用getAttribute()
方法并將屬性值打印輸出到屏幕中局骤。
There's more...
有時候你可能需要在XML文檔中查找一個特定的文本字符串攀圈。這就需要使用xml.parsers.expat
模塊。你需要從expat類中獲取一個搜索類峦甩,之后創(chuàng)建該類的一個對象赘来。創(chuàng)建完成后,你可以對搜索對象調(diào)用parse()
方法來查找數(shù)據(jù)凯傲。最后調(diào)用getElementsByTagName()
方法根據(jù)標(biāo)簽名稱來查找節(jié)點犬辰,這就返回一個與標(biāo)簽名稱有關(guān)的所有子節(jié)點列表。