1.哈希 hash
在將文件操作的方法之前,我們先來對上節的知識做一個拓展,就是哈希算法,那么什么是哈希算法呢?
(1)哈希:hash,一般翻譯做散列、雜湊,或音譯為哈希,是把任意長度的輸入(又叫做預映射pre-image)通過散列算法變換成固定長度的輸出,該輸出就是散列值。
這種轉換是一種壓縮映射,也就是,散列值的空間通常遠小於輸入的空間。
哈希算法的輸入可以是字符串,可以是數據,可以是任何文件,經過哈希運算后,都變成一個固定長度的輸出,該輸出就是哈希值。
>>> hash('我愛你')
3471388576844338423
>>> hash('小猿圈')
5000768010434506639
如上所示,輸入“我愛你”三個字,經過哈希運算后,會得到一個隨機數列,而且不管你的輸入文件多大,最后得到的結果都是這么一個固定長度的數列,即使你輸入的是一部電影,輸出也是這么大。
(2)特性:
1.不可逆性:在具備編碼功能的同時,哈希算法也作為一種加密算法存在。即,你無法通過分析哈希值計算出源文件的樣子。
無論是什么形式,任意大小的輸入,最終結果都是一串長度相等的隨機數列,因此你無法通過哈希值來推斷數據原本的樣子。
2.計算極快:不論是一個5G的電影還是一個5k的文件,運用哈希算法計算量都極小,很快就可以計算出哈希值。
(3)用途:
哈希算法的不可逆特性使其在以下領域使用廣泛
-
密碼,我們日常使用的各種電子密碼本質上都是基於hash的,你不用擔心支付寶的工作人員會把你的密碼泄漏給第三方,因為你的登錄密碼是先經過 hash+各種復雜算法得出密文后 再存進支付寶的數據庫里的
-
文件完整性校驗,通過對文件進行hash,得出一段hash值 ,這樣文件內容以后被修改了,hash值就會變。 MD5 Hash算法的”數字指紋”特性,使它成為應用最廣泛的一種文件完整性校驗和(Checksum)算法,不少Unix系統有提供計算md5 checksum的命令。
-
數字簽名,數字簽名技術是將摘要信息用發送者的私鑰加密,與原文一起傳送給接收者。接收者只有用發送者的公鑰才能解密被加密的摘要信息,然后用HASH函數對收到的原文產生一個摘要信息,與解密的摘要信息對比。如果相同,則說明收到的信息是完整的,在傳輸過程中沒有被修改,否則說明信息被修改過,因此數字簽名能夠驗證信息的完整性。
此外,hash算法在區塊鏈領域也使用廣泛。
(4)在Python中基於HASH的數據類型是dict (字典)和set (集合)。之前說到的字典查詢速度極快,以及集合天生去重就是運用了hash的特性。以下可以作一下了解。
1.dict查詢速度快
假設一個dict中有很多信息,dict會將每一個key進行哈希,將所有的哈希值按照從大到小的順序放到一個列表中,如keys=[ -22,-10,11,23,99]
當需要查找某個信息時,dict將被查找信息的key進行哈希,同一個輸入值進行哈希得到的哈希值時相等的,因此只需再列表中找到這個哈希值,就能找到對應的value。
那么問題來了,如果字典的數據比較小,計算機就能很快找到對應的值,但是如果字典中有幾十億條數據,怎么快速的找到對應的值呢?
dict采用的是二分法查找,即將被查找信息的key的哈希值與列表的中間的值比較大小,這樣就可以舍棄一半的值,這樣搜索區間就小了很多,多進行幾次這樣的操作,很快就可以找到對應的值。
這就是字典為何查詢速度快的基本原理,當然真實的算法會復雜的多。
2.set 天生去重
因為每存一個值到set里時, 都要先經過hash,然后通過得出的這個hash值算出應該存在set里的哪個位置,存的時候會先檢查那個位置上有沒有值 ,
有的話就對比是否相等,如果相等,則不再存儲此值。 如果不相等(即為空),則把新值存在這。
2.文件操作
Python的文件操作基本通過以下步驟
f = open(filename) # 打開文件
f.write("hello world") # 寫操作
f.read( ) # 讀操作
f.close( ) # 保存並關閉文件
常用操作模式
python文件有三種基本的操作模式
r 只讀模式
w 創建模式,不能讀,用此模式操作,新的內容會覆蓋舊的內容。即清空原來的內容,寫入新的內容。
a 追加模式 ,寫入的內容會追加到文件最后
只讀模式
f = open('filename.text', 'r') f.readline() # 讀一行內容 content = f.read() # 讀所有剩下的內容 print(content) f.close()
創建模式
f = open('filename.text', 'w') f.write('hello world') # 此時該文件的內容為hello world(不管原文件內容是什么) f.close()
追加模式
f = open('filename.text', 'a') f.write("小猿圈") # 此時文件內容為 hello world小猿圈 f.close()
循環文件
f = open('filename.tesxt' , 'r') for line in f: # 遍歷文件的每一行 print(line)
文件的其他操作功能
f = open('filename.text', 'r') f.mode # 返回文件的打開方式 f.name # 返回文件名 f.fileno() # 返回文件句柄在內核中的索引值,以后做IO多路復用時可以用到 f.flush() #將內容寫入硬盤時,由於硬盤的處理速度慢,內容會先在內存中,達到一定數量一# 起寫入硬盤提升效率,flush()方法可將內存中的數據寫入硬盤 f.readable() # 判斷文件是否可讀 f.readline() # 只讀一行,遇到\r 或 \n為止 f.seek() # 把操作文件的光標移動到指定位置 seek的長度是按字節算的 不同的編碼方式每 #個字符所占的字節不同。如gbk編碼下中文字符占兩個字節,utf-8編碼下中文字符占三個字 #節,如果讀取文件時的編碼方式不同會導致錯誤產生。 f.seekable() # 判斷文件是否能進行 seek 操作 f.tell() # 返回當前文件操作光標的位置 f.truncate() # 按指定長度截取文件 # 指定長度的話,就從文件開頭開始截斷指定長度; # 不指定長度的話,就從光標當前位置到文件 # 尾部的內容全去掉。 f.writeable() # 判斷文件是否可寫
混合模式
文件打開還有三種混合模式,既可以讀也可以寫。
w+ 寫讀 ,它會創建一個新文件 ,寫一段內容,可以再把寫的內容讀出來,一般不用。
r+ 讀寫,能讀能寫,但都是寫在文件最后,跟追加一樣,用的較多。
a+ 追加讀,文件一打開時光標會在文件尾部,寫的數據全會是追加的形式。
w+模式
f=open('filename.text','w+') # w+讀取時 光標在最后一行 讀取時需要指定光標 f.write("alex 23 male") f.seek(0) # 將光標移至開頭 再讀取 print(f.readline()) f.close()
r+模式
f = open('filename', 'r+') f.write() # 默認往文件尾部寫 f.readline() # 讀的是第一行
r+模式會將內容自動往文件末尾寫,但是如果想修改數據應該怎么辦?
將光標移動到中間的某一個位置,插入一個信息,會發現原來的信息會被寫入的信息所覆蓋。原因是,當你將文件存到硬盤上時,就在硬盤上划分了一段空間,空間就那么大,當你想寫入新的內容時,就只能覆蓋掉原來的數據,而不能使數據整體向后移。
如果想要修改文件,就只能將文件加載到內存當中,數據在內存當中可以隨便增刪改查,之后再將修改完的數據存入硬盤覆蓋掉原來的數據,就完成了文件的修改。
注:r+使用時,該文件必須存在。
當你想修改一份特別大的文件的時候,一下把文件加載到內存,是一種不明智的方式。如果想不占內存,可以采用一邊讀一邊寫的方式,就是創建一個新的文件,一邊從原文件中讀,一邊寫入新的文件。
f_name = "filename.txt" f_new_name = "%s.new" % f_name old_str = "eric" new_str = "alex" f = open(f_name,'r') # 打開原文件 f_new = open(f_new_name,'w') # 創建一個新文件 for line in f: # 讀原文件 if old_str in line: new_line = line.replace(old_str,new_str) # 修改文件 else: new_line = line f_new.write(new_line) 寫入新文件 f.close() f_new.close()
注:以上內容部分參考自路飛學城。
