配置文件的選擇
一、文件相關操作
不同模式打開文件的完全列表:
| 模式 | 描述 |
|---|---|
| r | 以只讀方式打開文件。文件的指針將會放在文件的開頭。這是默認模式。 |
| rb | 以二進制格式打開一個文件用于只讀。文件指針將會放在文件的開頭。這是默認模式。 |
| r+ | 打開一個文件用于讀寫。文件指針將會放在文件的開頭。 |
| rb+ | 以二進制格式打開一個文件用于讀寫。文件指針將會放在文件的開頭。 |
| w | 打開一個文件只用于寫入。如果該文件已存在則打開文件,并從開頭開始編輯,即原有內容會被刪除。如果該文件不存在,創建新文件。 |
| wb | 以二進制格式打開一個文件只用于寫入。如果該文件已存在則打開文件,并從開頭開始編輯,即原有內容會被刪除。如果該文件不存在,創建新文件。 |
| w+ | 打開一個文件用于讀寫。如果該文件已存在則打開文件,并從開頭開始編輯,即原有內容會被刪除。如果該文件不存在,創建新文件。 |
| wb+ | 以二進制格式打開一個文件用于讀寫。如果該文件已存在則打開文件,并從開頭開始編輯,即原有內容會被刪除。如果該文件不存在,創建新文件。 |
| a | 打開一個文件用于追加。如果該文件不存在則創建新文件進行寫入。 |
| ab | 以二進制格式打開一個文件用于追加。如果該文件不存在則創建新文件進行寫入。 |
| a+ | 打開一個文件用于讀寫。如果該文件已存在,文件指針將會放在文件的結尾。文件打開時會是追加模式。如果該文件不存在,創建新文件用于讀寫。 |
| ab+ | 以二進制格式打開一個文件用于追加。如果該文件已存在,文件指針將會放在文件的結尾。如果該文件不存在,創建新文件用于讀寫。 |
有文件config.txt如下,要讀取文件中的值
m_url=https://onetouch-partner.aba.com/login.htm? b_url=https://onetouch-partner.aba.com/ptnBasedata/crm/ c_url=https://onetouch-partner.aba.com/ptnBasedata/crm/customerList.htm titls=[公司名稱,創建時間,訪問時間,生成時間,簽約情況,跟進情況,公司地址,聯系人姓名,電話,企業郵箱,聯系人郵箱] filename=客戶信息 word=IDL2020888**
file 對象方法
f.read([size]):size 未指定則返回整個文件,如果文件大小 >2 倍內存則有問題,f.read()將整個文件內容作為一個字符串,讀到文件尾時返回""(空字串)。
f.readline():返回一行。
f.readlines([size]) :返回包含size行的列表, size 未指定則返回全部行。
for line in f: print line :通過迭代器訪問。
f.write("hello\n"):如果要寫入字符串以外的數據,先將他轉換為字符串。
f.close() 關閉文件
絕對路徑就是文件的真正存在的路徑,是指從硬盤的根目錄(盤符)開始,進行一級級目錄指向文件。
相對路徑就是以當前文件為基準進行一級級目錄指向被引用的資源文件。
../ 表示當前文件所在的目錄的上一級目錄
./ 表示當前文件所在的目錄(可以省略)
/ 表示當前站點的根目錄(域名映射的硬盤目錄)
py文件與要讀取文件在統一目錄下可直接讀取,不用家路徑
python中轉義用\,路徑用/,因此windows路徑可以是/(與linux一致)也可以用\\,Unix和Web用正斜杠/,Windows用反斜杠,但是現在Windows
python讀文件需要輸入的目錄參數,以下path都是正確的:
path1 = r"C:\Windows\temp\readme.txt" # "\"為字符串中的特殊字符,加上r后變為原始字符串,則不會對字符串中的"\t"、"\r" 進行字符串轉義
path2 = "c:\\windows\\temp\\readme.txt" # 用一個"\"取消第二個"\"的特殊轉義作用,即為"\\"
path3 = "c:/windows/temp/readme.txt" # 用正斜杠做目錄分隔符也可以轉到對應目錄,并且在python中path3的方式也省去了反斜杠\轉義的煩惱
二、常用配置文件格式
適合人類編寫:ini > toml > yaml > json > xml > plist
可以存儲的數據復雜度:xml > yaml > toml ~ json ~ plist > ini
ini,上古時代的配置文件,優點是簡單,缺點也是因為簡單。
XML,某段時期的特定產物,優點是某段時期很通用,缺點就是很難閱讀,一不小心寫錯。
JSON,網絡傳輸下的產品,大家發現它竟然意外的好用,做配置文件的話,易寫也易讀,你的代碼基本自帶解釋器,缺點嘛,不能寫注釋。但寫缺點,其實不過是加個字段來寫注釋的事,屬于強行幫它安個缺點。1.可讀性強,2.易上手,確定1.不支持注釋
YML,后面出來的配置文件,優點是能寫注釋,Spring boot框架默認配置格式,不用你額外寫什么代碼就能幫你搞定了解釋。缺點嘛,不適合寫復雜點的配置文件,配置文件也不能寫對象化的配置。yaml有點1.支持數據格式比較多樣,2.支持注釋容易發生空格引發的慘案。缺點:1.空格不利于修改編寫,2.不容易上手
三、txt
f = open(file) # 打開文件 content = f.read() print(content) f.close() # 關閉文件 #read with open('sample1.txt') as f: content = f.read() print(content) #readline讀取該文件: with open('a.txt') as f: print(f.readline()) print(f.readline(5)) #readlines方法沒有參數: with open('a.txt') as f: print(f.readlines()) f = open('sample3.txt','w') # 打開文件 content = f.write('hello,my friends!\nthis is python big data analysis') f.close() # 關閉文件 with open('sample3.txt','w') as f: f.write('hello,my friends!\nthis is python big data analysis')
def read_myconfig():
ss=[]
f = open("config.txt",'r',encoding='utf-8') #返回一個文件對象
# print(f)
for line in f:
ss.append(line.split('=')[1].strip("\n"))
f.close()
print(ss)
read_myconfig()
def read_myconfig():
ss=[]
f = open("config.txt",'r+',encoding='utf-8') #返回一個文件對象
line = f.read() #調用文件的 readline()方法
f.close()
# print(line.split('\n'))
for i in (line.split('\n')):
ss.append(i.split('=')[1])#以每行的換行劃分,將每行作為列表的一個元素。
print(ss)
read_myconfig()
def read_myconfig():
ss=[]
f = open("config.txt",'r+',encoding='utf-8') #返回一個文件對象
line = f.readline() #調用文件的 readline()方法
# print(line)
while line:
ss.append(line.split()[0].split('=')[1])#先過濾掉行末的換行
line = f.readline()
f.close()
print(ss)
read_myconfig()
def read_myconfig():
ss=[]
f = open("config.txt",'r',encoding='utf-8') #返回一個文件對象
line = f.readlines() #調用文件的 readline()方法
f.close()
# print(line)
for i in line:
ss.append(i.split('=')[1].strip("\n"))
print(ss)
read_myconfig()
def read_myconfig():
f = open("config.txt",'r',encoding='utf-8') #返回一個文件對象
line = f.readlines() #調用文件的 readline()方法
f.close()
# print(line)
ss=[i.split('=')[1].strip("\n") for i in line]
print(ss)
read_myconfig()
四、py
用Python變量作為配置文件格式
把配置直接用變量的形式寫到一個模塊中,在需要讀取配置的地方直接import模塊就能得到配置變量:
配置文件示例:
# config.py
listen_port = 4444
use_epoll = True
...
在讀取配置的地方:
import config
port_num = config.listen_port
if config.use_epoll:
...
優點
直接用python變量作為配置文件格式的優點是顯然的:
l 不用任何解釋器來解釋配置文件。Python解釋器本身就可以。
l 使用自然、方便,直接可用,和其他變量的使用沒有任何區別。
l 學習成本低,不需要學習其他配置文件的格式和語法。
缺點
方便之處在于不用parser,缺點也在于不用parser。通常情況,配置文件是人負責寫,程序負責讀。但如果配置文件既要讓人寫也要讓代碼寫。比如程序的配置可以直接改配置文件,同時也提供了一套界面讓用戶在界面上修改配置。在界面上修改的配置,最終也是反映到配置文件中,這就要求代碼修改配置文件了。此時會有少許不便。
五、ini
.ini、.txt配置文件使用方法是一致的,只是一個后綴的區別,這里以ini配置文件來介紹,這類配置文件我們使用內置configparser庫來使用,它可以實現配置文件的寫入、更新、刪除、讀取等操作非常方便,建議使用這種方式。新建一個config.ini的配置文件內容如下:
[mysql] name = admin host = 255.255.255.0 proxy = 6037 password = 123456 pool = true time = 3 #其中[]中的是section節點,該節點下的等式是鍵值對
常用方法如下:
# -*- coding: utf-8 -*-
import configparser
config = configparser.ConfigParser()
config.read("Config.ini", encoding="utf-8")
config.sections() # 獲取section節點
config.options('mysql') # 獲取指定section 的options即該節點的所有鍵
config.get("mysql", "name") # 獲取指定section下的options
config.items("mysql") # 獲取section的所用配置信息
config.set("mysql", "name", "root") # 修改值
config.has_section("mysql") # 是否存在該section
config.has_option("mysql", "password") # 是否存在該option
config.add_section("redis") # 添加section節點
config.set("redis", "name", "redis_admin") # 設置指定section 的options
config.remove_section("redis") # 整個section下的所有內容都將刪除
config.remove_option("mysql", 'time') # 刪除section下的指定options
config.write(open("Config", "w")) # 保存config
六,json
{ "GENERAL": { "domains": "tourism", "seed": "20230301" }, "logging": { "screen level": "results", "file_level": "results", "file": "auto" } }
讀取,實現了文件配置,缺點是無法寫注釋、無法寫過長或復雜的參數配置,容易出錯。
import json
with open('configs.json') as j:
cfg = json.load(j)['logging']
print(cfg)
# {'file': 'auto', 'file_level': 'results', 'screen_level': 'results'}
六、ymal
1、大小寫敏感
2、用縮進表示層級關系,縮進只能使用空格,不能用 TAB 字符,縮進的空格數量不重要,但是同一層級的元素左側必須對齊
# YAML
one:
two: 2
three:
four: 4
five: 5
// 以上的內容轉成 JSON 后
"one": {
"two": 2,
"three": {
"four": 4,
"five": 5
}
}
3、用 # 表示注釋,只支持單行注釋
4、一個文件中可以包含多個文件的內容
- 用“ --- ”即三個破折號表示一份內容的開始
- 用“ ... ”即三個小數點表示一份內容的結束(非必需)
---
# 這是第一份內容
one: 1
# 其他內容...
...
---
# 這是第二份內容
two: 2
# 其他內容...
5、對象(Mapping)
表示以鍵值對(key: value)形式出現的數據
- 使用“冒號+空格”來分開鍵與值
# YAML
key: value
// JSON
"key": "value"
- 支持多層嵌套(用縮進表示層級關系)
# YAML
key:
child-key1: value1
child-key2: value2
// JSON
"key": {
"child-key1": "value1",
"child-key2": "value2",
}
- 支持流式風格( Flow style)的語法(用花括號包裹,用逗號加空格分隔,類似 JSON)
# YAML
key: { child-key1: value1, child-key2: value2 }
// JSON
"key": { "child-key1": "value1", "child-key2": "value2" }
- 使用問號“?”聲明一個復雜對象,允許你使用多個詞匯(數組)來組成鍵
# YAML
?
- keypart1
- keypart2
:
- value1
- value2
6、數組(Sequence)
- 一組以區塊格式(Block Format)(即“破折號+空格”)開頭的數據組成一個數組
# YAML
values:
- value1
- value2
- value3
// JSON
"values": [ "value1", "value2", "value3" ]
- 同時也支持內聯格式(Inline Format)來表達(用方括號包裹,逗號加空格分隔,類似 JSON)
# YAML
values: [value1, value2, value3]
// JSON
"values": [ "value1", "value2", "value3" ]
- 支持多維數組(用縮進表示層級關系)
# YAML
values:
-
- value1
- value2
-
- value3
- value4
// JSON
"values": [ [ "value1", "value2"], ["value3", "value4"] ]
7、字符串(String)
- 字符串一般不需要用引號包裹,但是如果字符串中使用了反斜杠“\”開頭的轉義字符就必須使用引號包裹
# YAML
strings:
- Hello without quote # 不用引號包裹
- Hello
world # 拆成多行后會自動在中間添加空格
- 'Hello with single quotes' # 單引號包裹
- "Hello with double quotes" # 雙引號包裹
- "I am fine. \u263A" # 使用雙引號包裹時支持 Unicode 編碼
- "\x0d\x0a is \r\n" # 使用雙引號包裹時還支持 Hex 編碼
- 'He said: "Hello!"' # 單雙引號支持嵌套"
// JSON
"strings":
[ "Hello without quote",
"Hello world",
"Hello with single quotes",
"Hello with double quotes",
"I am fine. ?",
"\r\n is \r\n",
"He said: 'Hello!'" ]
- 對于多行的文字,YAML 提供了兩種特殊的語法支持
保留換行(Newlines preserved)
使用豎線符“ | ”來表示該語法,每行的縮進和行尾空白都會被去掉,而額外的縮進會被保留
# YAML
lines: |
我是第一行
我是第二行
我是吳彥祖
我是第四行
我是第五行
// JSON
"lines": "我是第一行\n我是第二行\n 我是吳彥祖\n 我是第四行\n我是第五行"
折疊換行(Newlines folded)
使用右尖括號“ > ”來表示該語法,只有空白行才會被識別為換行,原來的換行符都會被轉換成空格
# YAML
lines: >
我是第一行
我也是第一行
我仍是第一行
我依舊是第一行
我是第二行
這么巧我也是第二行
// JSON
"lines": "我是第一行 我也是第一行 我仍是第一行 我依舊是第一行\n我是第二行 這么巧我也是第二行"
8、布爾值(Boolean)
- “true”、“True”、“TRUE”、“yes”、“Yes”和“YES”皆為真
- “false”、“False”、“FALSE”、“no”、“No”和“NO”皆為假
# YAML
boolean:
- true # True、TRUE
- yes # Yes、YES
- false # False、FALSE
- no # No、NO
// JSON
"boolean": [ true, true, false, false ]
9、整數(Integer)
- 支持二進制表示
# YAML
int:
- 666
- 0001_0000 # 二進制表示
// JSON
"int": [ 666, 4096 ]
10、浮點數(Floating Point)
- 支持科學計數法
# YAML
float:
- 3.14
- 6.8523015e+5 # 使用科學計數法
// JSON
"float": [ 3.14, 685230.15 ]
11、空(Null)
- “null”、“Null”和“~”都是空,不指定值默認也是空
# YAML
nulls:
- null
- Null
- ~
-
// JSON
"nulls": [ null, null, null, null ]
12、時間戳(Timestamp)
- YAML 也支持 ISO 8601 格式的時間數據
這里使用 JavaScript 對象進行對比
# YAML
date1: 2020-05-26
date2: 2020-05-26T01:00:00+08:00
dete3: 2020-05-26T02:00:00.10+08:00
date4: 2020-05-26 03:00:00.10 +8
// JavaScript
date1: Tue May 26 2020 08:00:00 GMT+0800 (中國標準時間),
date2: Tue May 26 2020 01:00:00 GMT+0800 (中國標準時間),
dete3: Tue May 26 2020 02:00:00 GMT+0800 (中國標準時間),
date4: Tue May 26 2020 03:00:00 GMT+0800 (中國標準時間)
13、數據重用與合并
- 為了保持內容的簡潔,避免過多重復的定義,YAML 提供了由錨點標簽“&”和引用標簽“*”組成的語法,利用這套語法可以快速引用相同的一些數據...
# YAML
a: &anchor # 設置錨點
one: 1
two: 2
three: 3
b: *anchor # 引用錨點
// JSON
"a": {
"one": 1,
"two": 2,
"three": 3
},
"b": {
"one": 1,
"two": 2,
"three": 3
}
- 配合合并標簽“<<”使用可以與任意數據進行合并,你可以把這套操作想象成面向對象語言中的繼承...
# YAML
human: &base # 添加名為 base 的錨點
body: 1
hair: 999
singer:
<<: *base # 引用 base 錨點,實例化時會自動展開
skill: sing # 添加額外的屬性
programer:
<<: *base # 引用 base 錨點,實例化時會自動展開
hair: 6 # 覆寫 base 中的屬性
skill: code # 添加額外的屬性
// JSON
"human": { "body": 1, "hair": 999 },
"singer": { "body": 1, "hair": 999, "skill": "sing" },
"programer": { "body": 1, "hair": 6, "skill": "code" }
GENERAL: domains: tourism seed: 20230301 logging: screen_level: results file level: results file: auto
使用yaml的時候,我們不使用load()去加載,而是使用safe_load(),這樣去加載即可:
import yaml
from pprint import pprint
with open("config.yaml", "r") as config:
cfg = yaml.safe_load(config)
pprint(cfg)
pprint(cfg['logging'])
pprint(cfg['logging']['file'])
#輸出
{'GENERAL': {'domains': 'tourism', 'seed': 20230301},
'logging': {'file': 'auto',
'file level': 'results',
'screen_level': 'results'}}
{'file': 'auto', 'file level': 'results', 'screen_level': 'results'}
'auto'

浙公網安備 33010602011771號