3. 7 檔案
檔案讀取 (一)
使用 open 回傳設定輸入物件
使用 with open() as 設定輸入物件
3
infile = open(”fname”) # 設定 infile 物件讀取 fname 檔案
for line in infile : # 迴圈每次由 infile 讀一列存於 line 字串
print( line.strip() ) # 去除每列的前後空格後印出
infile.close() # 關檔
with open(”fname”) as infile : # 設定 infile 物件讀取 fname 檔案
for line in infile : # 每次由 infile 讀一列存於 line 字串
print( line.strip() ) # 去除每列的前後空格後印出
infile 離開 with . . . as 後,檔案自動關閉
檔案預設是以 utf-8 編碼,若是以 big5 編碼,需使用 encoding 參數
infile = open( ”fname”, encoding=’big5’ )
4. 7 檔案
檔案讀取 (二)
使用 with open() as 設定輸入物件
4
with open(”fname”) as infile : # 設定 infile 物件讀取 fname 檔案
for line in infile : # 每次由 infile 讀一列存於 line 字串
print( line.strip() ) # 去除每列的前後空格後印出
infile 離開 with . . . as 後,檔案自動關閉
以上迴圈中的 line 字串包含末尾換列字元(’n’),若不使用
line.rstrip()去除末尾空格字元(包含換列字元),則 print( line )
印完後會連跳兩列
5. 7 檔案
檔案讀取 (三)
讀取資料
readline():一次讀取一列資料成字串
readlines():以列為單位讀取剩餘資料成字串串列
read(n):讀取 n 個位元組
read():將剩餘資料串成一個字串
5
with open(”fname”) as infile :
print( infile.readline().rstrip() ) # 印出第一列去除右側空格資料
lines = infile.readlines() # 將剩餘列存入 lines 串列
# 也可寫成 lines = list(infile)
for line in lines : # 每列僅印前 12 個字元
print( line[:12] )
讀到末尾時,readline() 回傳空字串
6. 7 檔案
檔案寫入 (一)
使用 write 將字串寫入檔案
使用 open 設定輸出物件
6
# 將九九乘法表的輸出寫入 fname 檔案
outfile = open(”fname”,”w”)
for x in range(1,10) :
line = ””
for y in range(1,10) :
s = ”{0:3} x {1:1} = {2:>2}”.format(x,y,x*y)
line += s
# 將 line 字串透過 outfile 寫到 fname 檔案內
outfile.write(line+”n”)
outfile.close()
若寫入的檔案已經存在,則此檔會被移除後寫入
7. 7 檔案
檔案寫入 (二)
使用 with open as 設定輸出物件
7
with open(”fname”, ”w”) as outfile :
for x in range(1,10) :
for y in range(1,10) :
s = ”{0:3} x {1:1} = {2:>2}”.format(x,y,x*y)
line += s
# 將 line 字串透過 outfile 寫到 fname 檔
outfile.write(line+”n”)
使用 write 寫檔時,要自行加入換列字元(’n’)
8. 7 檔案
檔案寫入 (三)
writelines:將字串序列合併寫入檔案
with open(”fname”,”w”) as outfile :
8
# 型式一:寫入 1234 後換列
outfile.writelines( [ ”1” , ”2” , ”3” , ”4” ] + [ "n" ] )
# 型式二:寫入 1234 後換列
outfile.writelines( [ str(n) for n in range(1,5) ] + [ "n" ] )
# 型式三:寫入 1 2 3 4 共四列
outfile.writelines( [ str(n)+”n” for n in range(1,5) ] )
writelines 僅能處理字串串列
11. 7 檔案
混合讀檔、寫檔 (三)
with open as 同時設定輸出/輸入檔案
複製檔案
讀檔後新增各列號數存入新檔
11
with open("data1") as infile , open("data2","w") as outfile :
outfile.writelines( infile.readlines() )
with open("data1") as infile , open("data2","w") as outfile :
lines = infile.readlines()
fstr = "{:0>" + str(len(str(len(lines)))) + "}"
for i , line in enumerate(lines) :
line2 = fstr.format(i+1) + ": " + line
outfile.write(line2)
12. 7 檔案
檔案處理自動化 (一)
檔案處理自動化:一個程式可同時讀入許多檔,經過處理寫不同檔案。
檔名若有規則,則可建構檔名後隨即開檔:
將同乘數但不同被乘數的九九乘法公式寫到 9 個不同檔案:
12
for y in range(1,10) :
# 輸出的檔名依次為:mtable1、mtable2、mtable3、...
fname = "mtable" + str(y)
with open(fname,"w") as outfile :
for x in range(1,10) :
line = "{:1} x {:1} = {:>2}".format(x,y,x*y)
outfile.write(line+"n")
例如:mtable2 檔內存:
1 x 2 = 2
2 x 2 = 4
3 x 2 = 6
4 x 2 = 8
5 x 2 = 10
6 x 2 = 12
7 x 2 = 14
8 x 2 = 16
9 x 2 = 18
13. 7 檔案
檔案處理自動化 (二)
合併以上九個檔案成一個完整九九乘法表
13
lines = []
for y in range(1,10) :
fname = "mtable" + str(y)
with open(fname) as infile :
for i , line in enumerate(infile) :
if y == 1 :
lines.append( line.rstrip() )
else :
lines[i] += " | " + line.rstrip()
print( "n".join(lines) )
輸出為:
1 x 1 = 1 | 1 x 2 = 2 | 1 x 3 = 3 ... 1 x 8 = 8 | 1 x 9 = 9
2 x 1 = 2 | 2 x 2 = 4 | 2 x 3 = 6 ... 2 x 8 = 16 | 2 x 9 = 18
3 x 1 = 3 | 3 x 2 = 6 | 3 x 3 = 9 ... 3 x 8 = 24 | 3 x 9 = 27
4 x 1 = 4 | 4 x 2 = 8 | 4 x 3 = 12 ... 4 x 8 = 32 | 4 x 9 = 36
5 x 1 = 5 | 5 x 2 = 10 | 5 x 3 = 15 ... 5 x 8 = 40 | 5 x 9 = 45
6 x 1 = 6 | 6 x 2 = 12 | 6 x 3 = 18 ... 6 x 8 = 48 | 6 x 9 = 54
7 x 1 = 7 | 7 x 2 = 14 | 7 x 3 = 21 ... 7 x 8 = 56 | 7 x 9 = 63
8 x 1 = 8 | 8 x 2 = 16 | 8 x 3 = 24 ... 8 x 8 = 64 | 8 x 9 = 72
9 x 1 = 9 | 9 x 2 = 18 | 9 x 3 = 27 ... 9 x 8 = 72 | 9 x 9 = 81
14. 7 檔案
命令列參數
使用 sys 套件的 sys.argv 串列取得命令列參數:
範例:列印檔案列數
14
import sys
for x in sys.argv : print(x)
命令列執行:
> python3 foo.py aa bb cc
foo.py 的 sys.argv = [’foo.py’, ’aa’, ’bb’, ’cc’]
sys.argv 第一個字串為程式檔名,之後則為命令列參數字串
import sys
# 由命令列取得檔案名稱,輸出檔名及其列數
for file in sys.argv[1:] :
with open(file) as infile :
print( file , len(infile.readlines()) )
35. 7 檔案
世界各國教育支出比例排名 (二)
35
以上每一列資料依次為國名、GDP 百分比、統計年度、註解。資料中
有些國家的名稱可能不只為一個字。若該國家沒有 GDP 百分比時則以
n.a. 替代。
現在我們要撰寫程式重新以 GDP 的百分比由大到小排列,沒有 GDP
百分比的國家排列在最後,同時將資料以橫線替代。此外如果 GDP 百分比
一樣的國家,則按照國家名稱的字母順列排列。以下程式要輸出的內容:
36. 7 檔案
世界各國教育支出比例排名 (三)
36
由以上的輸出規定,本範例在讀入資料檔後要依 GDP 支出百分比排序
,同時在列印時除了要改變資料排列格式外,也要微幅更改呈現資料,這樣
的簡單要求是試算表程式無法勝任的,通常透過程式設計才能處理。一般來
說,資料處理是 python 程式語言的強項,經常只要短短的幾十列程式就
能解決大多數問題。
以下的程式大致區分為兩部份,第一部份為讀檔,檔案的每一列包含國
名、GDP、年份、來源等等,仔細觀察資料,發現有些國家的名稱超過一個
字,此時可使用星號式子將國名先存為字串串列,之後在將其合併為單一字
串。程式的第二部份為排序,在 sorted 函式內定義排序標準,回傳排序
串列用來表示資料是先依 GDP 百分比由大到小,再依國名字母順序排列。
最後在程式末尾使用 format 重新排列資料後列印。
37. 7 檔案
世界各國教育支出比例排名 (四)
37
nations , gdps , years = [] , [] , []
with open("edu.dat") as infile :
for line in infile :
if line.isspace() : continue
# 星號將多字串的國家名稱儲存到串列
*nation , gdp , year , src = line.split()
# 儲存國名與年度資料於串列
nations.append( " ".join(nation) )
years.append( year )
# 沒有資料時,gdp 以 -1 替代
if year == "n.a." :
gdps.append( -1 )
else :
gdps.append( float(gdp) )
38. 7 檔案
世界各國教育支出比例排名 (五)
38
i = 1
# 依 gdp 由大到小,國名依字母順序排列
for nation , gdp , yr in sorted( zip(nations,gdps,years) ,
key=lambda p : ( -p[1] , p[0] ) ) :
if gdp == -1 :
line = "{:>3}:{:>5} [{:>4}] {:}".format( i , "---" ,
yr , nation )
else :
line = "{:>3}:{:>5.1F} [{:>4}] {:}".format( i , gdp ,
yr , nation )
print( line )
i += 1
45. 7 檔案
習題 6
45
ROT13 是一種簡單的替換式密碼法,可很快的將英文密碼化,逃過
他人的眼目一瞥。
此種方法是將 26 個英文字母排成圓環,不管是加密/解密都是將
讀入的字母旋轉 13 個位置,也就是:
加密/解密過程中仍保持字母的大小寫,請撰寫程式讀入以下英文檔
,使用 ROT13 加密後存入新檔。
The Quick Brown Fox Jumps Over The Lazy Dog.
Gur Dhvpx Oebja Sbk Whzcf Bire Gur Ynml Qbt.
原始字母:A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
對應字母:N O P Q R S T U V W X Y Z A B C D E F G H I J K L M
46. 7 檔案
習題 7
46
以下檔案為某公司六個部門對某產品在各季節的銷售量:
撰寫程式讀入檔案,輸出各部門各季節累積的銷售量如下:
A B C D E F
spring 10 23 14 17 20 22
summer 16 20 22 18 25 19
autumn 15 16 23 20 24 14
winter 12 22 14 24 18 20
前1季 前2季 前3季 前4季
A 10 26 41 53
B 23 43 59 81
C 14 36 59 73
D 17 35 55 79
E 20 45 69 87
F 22 41 55 75