為什么要序列化
內存中的字典、列表、集合以及各種對象,如何保存到一個文件中。
設計一套協議,按照某種規則,把內存中的數據保存到文件中,文件是一個個字節序列。所以必須把數據額轉換為字節序列,輸出到文件,這就是序列化,反之,從文件的字節 序列恢復到內存中,就是反序列化。
1、定義
Serialization系列化,將內存中對象存儲下來,把他變成一個個字節。二進制。
deSerialization反序列化,將文件的一個個字節到內存中。
序列胡保存到文件就是持久化。
可將數據序列化后持久化,或者網絡傳輸,也可以將文件中或者網絡接受到的字節序列反序列化。
2、pickle庫
Python中的序列化、反序列化模塊
dumps對象序列化為bytes對象
dump對象序列化到文件對象,就是存入到文件。
loads從bytes對象反序列化。
load對象反序列化,從文件讀取數據.
##
import pickle
filename = 'ser'
x= 'a'
y = '100'
z = '100'
with open(filename,'wb') as f:
pickle.dump(x,f)
pickle.dump(y,f)
pickle.dump(z,f)
with open(filename,'rb')as f:
for _ in range(3):
a = pickle.load(f)
print(a,type(a))
還原的時候不一定是完全一樣的。
序列化應用:一般來說,本地序列化的情況,應用較少,大多數都是用在網絡傳輸上面的。
將數據序列化后通過網絡傳輸到遠程節點,遠程服務器上的服務將接受到的數據反序列化后,就可以使用了。
但是,要注意的是,遠程接收端,反序列化時候必須有對應的數據類型,否則就會報錯。尤其是自己定義的類。必須遠程得有一致的定義。
3、Json
1)是一種輕量級的數據交換格式,基於ECMAScript(w3c制定的JS規范)的一個子集,采用完全獨立於編程語言的文本格式來存儲和表示數據。
2)數據類型
值
雙引號引起來的字符串,數值,true和flase,null,對象,數組,這些都是值。
字符串
由雙引號包圍起來的任意字符的組合,可以有轉義字符。
數值:有正負,整數,浮點數。
對象:無序的鍵值對的集合。
格式:{key1:value1,.....keyn:valuen}
Key必須是一個字符串,需要雙引號包圍這個字符。
Value可以是任意合法的值。
數組:有序的值的集合
格式:[value1,....valuen]
例子:
2) json模塊
Python與json
Python支持少量內建數據類型到json類型的轉換。
| Python類型 |
Json類型 |
| True |
True |
| False |
False |
| None |
Null |
| Str |
String |
| Int |
Integer |
| Float |
Float |
| List |
Array |
| Dict |
obiect |
3) 常用的方法
| Python 類型 |
Json類型 |
| Dumps |
Json編碼 |
| Dump |
Json編碼並寫入文件 |
| Loads |
Json解碼 |
| Load |
Json解碼,從文件讀取數據 |
import json
d = {'name':'tom','age':20,'interest':['music','movie']}
j = json.dumps(d)
print(j)
d1 = json.loads(j)
print(d1)
{"name": "tom", "age": 20, "interest": ["music", "movie"]}
{'name': 'tom', 'age': 20, 'interest': ['music', 'movie']}
一般json編碼的數據就很少落地,數據都是通過網絡傳輸。傳輸的時候要考慮壓縮。
本質上來說就是一個文本,就是個字符串。
Json很簡單,幾乎語言編程都支持json,所以應用范圍十分廣泛。
4、MessagePack
是一個基於二進制高效的對象化序列類庫,可用於跨語言通信。
可以像json那樣,在許多種需要之間交換結構對象。
比json更快速也更輕巧。
支持python,ruby,java,C/C++等眾多語言。
安裝:
Pip install msgpack-python
常用方法
Packb序列化對象,提供了dumps兼容pickle和json
Unpackb反序列化對象,提供了loads來兼容
Pack序列化對象保存到文件對象,提供了dump來兼容
Unpack反序列化對象保存到文件對象,提供了load來兼容。
##
import json
import msgpack
d = {'person':[{'name':'tom','age':18},{'name':'jerry','age':16}],'total':2}
j = json.dumps(d)
m =msgpack.dumps(d)
print('json={},msgpack={}'.format(len(j),len(m)))
print(j.encode(),len(j.encode()))
print(m)
u = msgpack.unpackb(m)
print(type(u),u)
u = msgpack.unpackb(m,encoding='utf-8')
print(type(u),u)
MessagePack簡單易用,高效壓縮,支持的語言豐富
序列化也是一種很好的選擇。
簡單易用,高效壓縮,支持語言豐富,所以,用它序列化是一種很好的選擇。
6、argparse模塊
1)一個可執行文件或者腳本都可以接收參數。
ls -l/etc /etc是位置參數 -l 是短選項
如何將參數傳遞到程序,就使用參數分析模塊argparse
1) 參數分類。
參數分為:位置參數,參數放在哪里,就要對應一個參數位置,例如/etc 就是對應的一個參數位置。
選項參數,必須通過前面 - 的短選項或者 --的長選項,然后后面的才算是參數,短選項后面也可以沒有參數。
/etc 對應的就是位置參數, -l是選項參數。
3)基本解析
import argparse
parser = argparse.ArgumentParser()
args = parser.parse_args()
parser.print_help()
usage: argparse模塊使用.py [-h]
optional arguments:
-h, --help show this help message and exit
Argparse不僅僅做了參數的定義和解析,還自動生成了幫助信息。Usage,可以看到現在定義的參數是否是自己想要的。
4)解析器的參數
| 參數名稱 |
說明 |
| Prog |
程序的名字,缺省使用,sys.argv[0] |
| add_help |
自動生成解析器增加 - h和--help選項,默認為True |
| description |
為程序添加功能描述 |
import argparse
parser = argparse.ArgumentParser(prog= 'ls',add_help=True,description='list directorycontents')
args = parser.parse_args()
parser.print_help()
usage: ls [-h]
list directorycontents
optional arguments:
-h, --help show this help message and exit
2) 位置參數解析器
ls 基本功能解決目錄內容的打印。
打印的時候應該制定目錄路徑,需要的位置參數。
import argparse
parser = argparse.ArgumentParser(prog= 'ls',add_help=True,description='list directorycontents')
parser.add_argument('path')
args = parser.parse_args() #分析參數
parser.print_help() #打印幫助
usage: ls [-h] path
ls: error: the following arguments are required: path
程序等定義為
ls [-h] path
-h為幫助,可有可無
path 為位置參數,必須提供。
6)傳參
Parse_args(args=None,namespace=None)
args參數列表,一個可迭代對象,內部會把可迭代對象轉換成list,如果為None則使用命令行傳入參數,非None則使用args參數的可迭代對象。
import argparse
parser = argparse.ArgumentParser(prog= 'ls',add_help=True,description='list directorycontents')
parser.add_argument('path') #位置參數
args = parser.parse_args(('/etc',)) #分析參數
print(args) #打印名詞空間中收集的參數
parser.print_help() #打印幫助
Namespace(path='/etc')
usage: ls [-h] path
list directorycontents
positional arguments:
path
optional arguments:
-h, --help show this help message and exit
Namespace(path='/etc')里面的path參數存儲在一個Namespace對象內的屬性上,,可以通過Namespace對象屬相來訪問。args.path
7)非必須位置參數。
必須輸入位置參數,否則會報錯。
有些時候ls命令不需要輸入任何路徑就表示列出當前目錄的文件列表。
import argparse
parser = argparse.ArgumentParser(prog= 'ls',add_help=True,description='list directorycontents')
parser.add_argument('path',nargs='?',default='.',help='path help') #位置參數,可有,可無,缺省值,幫助
args = parser.parse_args() #分析參數
print(args) #打印名詞空間中收集的參數
parser.print_help() #打印幫助
Namespace(path='.')
usage: ls [-h] [path]
list directorycontents
positional arguments:
path path help
optional arguments:
-h, --help show this help message and exit
看到path也變成了可選位置參數,沒有提供默認值.表示當前的路徑。
.help表示幫助文檔中這個參數的描述。
.nargs表示這個參數接受結果參數,?表示可有可無,+表示至少一個,*表示任意個,數字表示必須是制定數目個。
.default表示如果不提供該參數,就一直使用這個值,一般和?、*配合,因為他們都可以不提供位置參數,不提供就是使用缺省值。
8)選項參數
-l 的實現:
-a 的實現。長選項同時給出,
import argparse
parser = argparse.ArgumentParser(prog= 'ls',add_help=True,description='list directorycontents')
parser.add_argument('path',nargs='?',default='.',help='path help') #位置參數,可有,可無,缺省值,幫助
parser.add_argument('-l',action ='store_true',help = 'use a one listing format')
parser.add_argument('-a','--all',action ='store_true',help='show all files,do not ignore entries starting with .')
args = parser.parse_args() #分析參數
print(args) #打印名詞空間中收集的參數
parser.print_help() #打印幫助
Namespace(all=False, l=False, path='.')
usage: ls [-h] [-l] [-a] [path]
list directorycontents
positional arguments:
path path help
optional arguments:
-h, --help show this help message and exit
-l use a one listing format
-a, --all show all files,do not ignore entries starting with .
1) ls 業務功能的實現。
上面解決了參數的定義和傳參的問題,下面解決業務問題:
(1) .列出所有指定路徑的文件,默認是不遞歸的。
(2) -a顯示所有文件,包括隱藏文件。
(3) -l詳細列表模式顯示。
代碼實現:listdirdetail和listdir
import argparse
from pathlib import Path
from datetime import datetime
#獲得一個參數解析器
parser = argparse.ArgumentParser(prog= 'ls',add_help=True,description='list directorycontents')
parser.add_argument('path',nargs='?',default='.',help='path help') #位置參數,可有,可無,缺省值,幫助
parser.add_argument('-l',action ='store_true',help = 'use a one listing format')
parser.add_argument('-a','--all',action ='store_true',help='show all files,do not ignore entries starting with .')
args = parser.parse_args() #分析參數
print(args) #打印名詞空間中收集的參數
parser.print_help() #打印幫助
def listdir(path,all=False):
p = Path(path)
for i in p.iterdir():
if not all and i.name.startswith('.'): #不顯示隱藏文件
continue
yield i.name
print(list(listdir(args.path)))
#獲取文件類型
def _getfiletype(f:path):
# f = Path(path)
if f.is_dir():
return 'd'
elif f.is_block_device():
return 'b'
elif f.is_char_device():
return 'c'
elif f.is_socket():
return 's'
elif f.is_symlink():
return 'l'
else:
return '-'
##顯示文件權限等 mode
modelist = dict(zip(range(9),['r','w','x','r','w','x','r','w','x']))
def _getmodestr(mode:int):
m = mode &0o777
mstr = ''
for i in range(8,-1,-1):
if m >>i & 1:
mstr += modelist[8-i]
else:
mstr +='-'
return mstr
def listdirdetail(path,all=False,detail=False):
p = Path(path)
for i in p.iterdir():
if not all and i.name.startswith('.'):
continue
if not detail:
yield (i.name,)
else:
stat = i.stat()
# t = _setfiletype(i)
mode = _getfiletype(i)+_getmodestr(stat.st_mode)
atime = datetime.fromtimestamp(stat.st_atime).strptime('%Y %m %d %H:%M:%S')
yield (mode,stat.st_nlink,stat.st_uid,stat.st_gid,stat.st_size,atime,i.name)
for x in listdir(args.path):
print(x)
Mode是整數,八進制描述的權限,最終顯示rwx的格式。
modelist = dict(zip(range(9),['r','w','x','r','w','x','r','w','x']))
def _getmodestr(mode:int):
m = mode &0o777
mstr = ''
for i in range(8,-1,-1):
if m >>i & 1:
mstr += modelist[8-i]
else:
mstr +='-'
return mstr
2) 排序
顯示的文件按照文件名的升序排序輸出。
Sorted(listdir(args.path,detail=True),key=lambda x:x[len(x)-1])
3) 完整代碼:
import argparse
from pathlib import Path
from datetime import datetime
#獲得一個參數解析器
parser = argparse.ArgumentParser(prog= 'ls',add_help=True,description='list directorycontents')
parser.add_argument('path',nargs='?',default='.',help='path help') #位置參數,可有,可無,缺省值,幫助
parser.add_argument('-l',action ='store_true',help = 'use a one listing format')
parser.add_argument('-a','--all',action ='store_true',help='show all files,do not ignore entries starting with .')
def listdir(path,all=False,detail=False):
def _getfiletype(f: path):
if f.is_dir():
return 'd'
elif f.is_block_device():
return 'b'
elif f.is_char_device():
return 'c'
elif f.is_socket():
return 's'
elif f.is_symlink():
return 'l'
else:
return '-'
modelist = dict(zip(range(9), ['r', 'w', 'x', 'r', 'w', 'x', 'r', 'w', 'x']))
def _getmodestr(mode: int):
m = mode & 0o777
mstr = ''
for i in range(8, -1, -1):
if m >> i & 1:
mstr += modelist[8 - i]
else:
mstr += '-'
return mstr
def _listdir(path, all=False, detail=False):
p = Path(path)
for i in p.iterdir():
if not all and i.name.startswith('.'):
continue
if not detail:
yield (i.name,)
else:
stat = i.stat()
# t = _setfiletype(i)
mode = _getfiletype(i) + _getmodestr(stat.st_mode)
atime = datetime.fromtimestamp(stat.st_atime).strptime('%Y %m %d %H:%M:%S')
yield (mode, stat.st_nlink, stat.st_uid, stat.st_gid, stat.st_size, atime, i.name)
yield from sorted(_listdir(path, all, detail), key=lambda x: x[len(x) - 1])
if __name__ == '__main__':
args = parser.parse_args() # 分析參數
print(args) # 打印名詞空間中收集的參數
parser.print_help() # 打印幫助
files = listdir(args.path,args.all,args.l)
4) -h的實現
-h ,-human-readable,如果-l存在,-h有效。
import argparse
from pathlib import Path
from datetime import datetime
parser = argparse.ArgumentParser(prog='ls',description='list directory contents',add_help=False)
parser.add_argument('path',nargs='?',default='.',help='path help')
parser.add_argument('-h','--human-readable',action='store_true',help='with -l,print sizes in human readable format')
# args = parser.parse_args() # 分析參數
# print(args) # 打印名詞空間中收集的參數
# parser.print_help() # 打印幫助
def listdir(path,all=False,detail=False,human=False):
def _getfiletype(f:path):
"""獲取文件的類型"""
if f.is_dir():
return 'd'
elif f.is_block_device():
return 'b'
elif f.is_char_device():
return 'c'
elif f.is_socket():
return 's'
elif f.is_symlink():
return 'l'
elif f.is_fifo():
return 'p'
else:
return '-'
modelist = dict(zip(range(9),['r', 'w', 'x', 'r', 'w', 'x', 'r', 'w', 'x']))
def _getmodest(mode:int):
m =mode & 0o777
mstr = ''
for x in range(8,-1,-1):
if m >> i & 1:
mstr += modelist[8-i]
else:
mstr += '-'
return mstr
def _gethuman(size: int):
units = 'KMGTP'
depth = 0
while size >= 1000:
size = size // 1000
depth += 1
return '{}{}'.format(size, units[depth])
def _listdir(path,all=False,detail=False,human=False):
p =Path(path)
for i in p.iterdir():
if not all and i.name.startswith('.'):
continue
if not detail:
yield (i.name,)
else:
stat = i.stat()
# t = _setfiletype(i)
mode = _getfiletype(i) + _getmodestr(stat.st_mode)
atime = datetime.fromtimestamp(stat.st_atime).strptime('%Y %m %d %H:%M:%S')
yield (mode, stat.st_nlink, stat.st_uid, stat.st_gid, stat.st_size, atime, i.name)
yield from sorted(_listdir(path, all, detail), key=lambda x: x[len(x) - 1])
if __name__ == '__main__':
args = parser.parse_args() # 分析參數
print(args) # 打印名詞空間中收集的參數
parser.print_help() # 打印幫助
files = listdir(args.path,args.all,args.l)
5) 改進mode的模塊
使用stat模塊
import stat
from pathlib import Path
stat.filemode(Path().stat().st_mode)
6) 最終代碼:
import argparse
import stat
from pathlib import Path
from datetime import datetime
parser = argparse.ArgumentParser(prog='ls',description='list directory contents',add_help=False)
parser.add_argument('path',nargs='?',default='.',help='path help')
parser.add_argument('-h','--human-readable',action='store_true',help='with -l,print sizes in human readable format')
parser.add_argument('-l',action ='store_true',help = 'use a one listing format')
parser.add_argument('-a','--all',action ='store_true',help='show all files,do not ignore entries starting with .')
# args = parser.parse_args() # 分析參數
# print(args) # 打印名詞空間中收集的參數
# parser.print_help() # 打印幫助
def listdir(path,all=False,detail=False,human=False):
def _gethuman(size: int):
units = 'KMGTP'
depth = 0
while size >= 1000:
size = size // 1000
depth += 1
return '{}{}'.format(size, units[depth])
def _listdir(path, all=False, detail=False, human=False):
p = Path(path)
for i in p.iterdir():
if not all and i.name.startswith('.'):
continue
if not detail:
yield (i.name,)
else:
st = i.stat()
# t = _setfiletype(i)
mode = stat.filemode(st.st_mode)
atime = datetime.fromtimestamp(st.st_atime).strptime('%Y %m %d %H:%M:%S')
size = str(st.st_size) if not huam else _gethuman(st.st_size)
yield (mode, st.st_nlink, st.st_uid, st.st_gid, size, atime, i.name)
yield from sorted(_listdir(path, all, detail), key=lambda x: x[len(x) - 1])
if __name__ == '__main__':
args = parser.parse_args() # 分析參數
print(args) # 打印名詞空間中收集的參數
parser.print_help() # 打印幫助
files = listdir(args.path, args.all, args.l)
