第四章 文件和目錄工具

文件工具:python

經過內建庫函數和標準庫來對文件進行操縱;sql

內建函數open是用來在計算機底層系統下訪問文件的工具,它是python的固有部分,被調用返回一個新的與文件相連的對象shell

經過內建模塊os 能夠操做較底層的基於描述符的文件,複製,移除,移動和手機文件(os和shutil),藉助字典的鍵將數據和對象存儲於文件中(dbm和shelve) 以及訪問sql數據庫(sqllit第三方插件)數據庫


python3.x中的文件對象模型python3.x

  • 文本文件含有unicode文本(內容始終是一個str字符串----字符構成的序列)緩存

  • 二進制文件包含原有的8位字節碼(內容始終是字節字符串----小整數構成的序列)
    dom


使用內建文件對象函數

輸出文件:工具

f=open('file','w')    以寫方式打開文本文件性能

f.write('string\n')    寫入文件

f.writelines(['str1\n','str2\n'])    寫入行字符列表到文件

f.close()    關閉文件

open('file.txt','w').write('str\n')    建立臨時文件對象並寫入數據,立刻被使用不須要保存對象的引用,數據傳輸完成後問擊案對象立刻就被回收並在進程中自動關閉


確保文件關閉:異常處理和上下文管理

萬能的處理模式:

myfile=open('file','w')

     try:

        ...process myfile...

    finally:

         myfile.close()

這是使用最普遍的方法,確保發生異常停止時 關閉文件

文件上下文管理器(這個語句依賴與文件上下文):

with open(filename) as myfile:

    subprocess...

這種語句不管是否發生異常都不要手動去關閉文件。

大多數狀況下上面的兩種語句不多用的到,由於標準cpython在回收時自動關閉文件。


輸入文件

file=open('file.txt','r')    打開輸入文件對象,默認值爲'r'

file.read()     一次性讀取整個文件,返回一個字符串(包含文本全部字符(或字節))

file.read(n)     讀取接下來的n個字符

file.readline()    讀取下一個\n以前的內容並返回一個字符串 

file.readlines()    讀取整個文件並返回一個行字符串列表

file.seek()    指定文件內容的偏移位置


 使用文件迭代器讀取行

f=open(filename)

for line in f:

   ...do...

更妙的是:

for line in open(data.txt):

   ..something.......

循環中把文件做爲臨時文件對象打開,在循環結束後的垃圾回收時自動關閉。並且這個文件行迭代器不是一次性把整個文件加載到行列表,所以在處理大文件時較爲節省空間。你也能夠經過手動方式調用迭代器 它是一個__next__方法(由內建函數next運行)與每次調用readline()方法相似,只是read方法在文件末尾EOF返回一個空字符,而迭代器則拋出一個異常來結束迭代


有趣的是,在全部跌打情境下,迭代器都自動得以使用,這些情景包括list構造調用,列表解析表達式,map調用,以及in成員關係檢查

>>> open('txt').readlines()                    #老是讀取多行
['hello word\n', 'bye lixing\n']               
>>> list(open('txt'))                        #強制逐行迭代
['hello word\n', 'bye lixing\n']
>>> lines=[line.rstrip() for line in open('txt')]  #解析
>>> lines
['hello word', 'bye lixing']
>>> lines=[line.upper() for line in open('txt')]   #任意操做
>>> lines
['HELLO WORD\n', 'BYE LIXING\n']
>>> list(map(str.split,open('txt')))             #應用函數
[['hello', 'word'], ['bye', 'lixing']]
>>> line='hello word\n'                        #判斷文件是否含有該行
>>> line in open('txt')
True


其餘打開選項

open開文件用三個參數:

  • 文件名 

                文件名能夠包含一個顯示的目錄路徑,沒有顯示路徑,就採用當前工做的目錄。在win下打開文件時由於要使用                       r'c:\dr\txt'模式來消除轉義 . 當前目錄,..父目錄

  • 打開模式

             open函數也接受其餘模式,r+ w+ a+表示讀取寫入和追加的模式,b二進制模式 t文本模式   rb以二進制讀取模式 wb以二進制寫 ab以二進制追加, rb+ wb+ ab+把二進制輸入 輸出 結合起來

  • 緩存策略

    0表示無緩衝 1表示緩衝


二進制和文本文件

文件與程序之間傳輸的數據,即便是二進制數據,在腳本中仍是表示爲python字符串。對於二進制模式文件,文件內容則表示爲字節字符串。文件實例:

>>> open('data.txt','w').writelines(['hello word\n','bye file word\n','the life of brian\n'])
>>> open('data.txt','r').read()
'hello word\nbye file word\nthe life of brian\n'
>>> open('data.txt','rb').read()
b'hello word\nbye file word\nthe life of brian\n'
>>> for line in open('data.txt','rb'):     
...  print(line)\
... 
... 
b'hello word\n'
b'bye file word\n'
b'the life of brian\n'
>>>

產生上述結果的緣由是python3.x把文本模式文件當作unicode來處理,並自動地在輸入時對文件進行解碼,在輸出時進行編碼。

謹記:必須在二進制模式下打開真正的二進制數據,由於二進制數據做爲unicode文本時是不會發生解碼編碼等操做的。二進制模式不只使unicode編碼轉換沒法進行,還阻止了文本模式文件默認換行符的自動轉換。


文本文件的unicode編碼

以下包含一個unicode字符的字符串:

>>> data='sp\xe4m'
>>> data
'späm'
>>> 0xe4
228
>>> bin(0xe4)
'0b11100100'
>>> chr(0xe4)
'ä'
>>> data.encode('latin1')
b'sp\xe4m'
>>> data.encode('utf8')
b'sp\xc3\xa4m'
>>> data.encode('acsii')
Traceback (most recent call last):                 
  File "<stdin>", line 1, in <module>
LookupError: unknown encoding: acsii

編碼結果反映了其存儲於文件中原始二進制形式。不過一般不用手動編碼,由於文本文件在數據傳輸的時候會自動編碼。


看下面代碼:

>>> open('data.txt','w',encoding='latin1').write(data)
4
>>> open('data.txt','r',encoding='latin1').read()
'späm'
>>> open('data.txt','rb').read()
b'sp\xe4m'

若是咱們在二進制模式下打開文件,是不會發生編碼轉換的,爲了瞭解文件內容和其餘編碼之間的區別,再次保存這些一樣的字符串:

>>> open('data.txt','w',encoding='utf8').write(data)
4
>>> open('data.txt','r',encoding='utf8').read()
'späm'
>>> open('data.txt','rb').read()
b'sp\xc3\xa4m'

這一次雖然原始文件內容有所不一樣,但文本模式的自動解碼使得字符串在腳本讀取返回以前相等。其實編碼只與文件中的字符串有關,前面說過對於文本文件python3.x都是當成unicode來處理,字符串一旦載入內存就成了簡單的unicode字符序列(即‘碼點’).轉換的步驟正是咱們但願對文本而非二進制文件進行的操做。由於二進制模式跳過了轉換。

再次提醒:二進制模式打開文件不會 進行任何轉換!!!!!!!!!!!!!!!!


用struct模塊解析打包的二進制數據

該模塊用於打包和解壓二進制數據的調用,可以用你想用的任何一種字節序來進行組合和分解。

以下代碼:

>>> import struct
>>> data=struct.pack('>i4shf',2,'spam'.encode('utf8'),4,1.234)
>>> data
b'\x00\x00\x00\x02spam\x00\x04?\x9d\xf3\xb6'
>>> open('data.bin','wb').write(data)
14
>>> open('data.bin','rb').read()
b'\x00\x00\x00\x02spam\x00\x04?\x9d\xf3\xb6'
>>> struct.unpack('>i4shf',open('data.bin','rb').read())
(2, b'spam', 4, 1.2339999675750732)

python在這裏用十六進制轉義序列\xn的形式展現大部分打包後的二進制數據的字節,由於這些字節都是不可打印字符串。解析剛生成的這種數據,從文件中讀取並以一樣的格式字符串將其傳入struct模塊--將獲得一個元組,它包含從字符串解析出來的數值以及轉換爲python對象的數值。-----詳細瞭解struct就看python庫手冊吧


隨機訪問文件

二進制文件中常常可見隨機訪問處理操做。文件的open模式字符串添加+號後可讀也可寫。這種模式一般與文件對象的seek方法聯合使用,以便支持隨機讀取和寫入訪問。

Python的Seek方法也能夠接受可選的第二種參數,這個參數有三種值:

0:表示絕對文件位置(默認值)

1:表示尋找 的是基於當前所在的相對位置

2:表示尋求基於文件結尾的相對位置


在wb+模式下建立一個文件,並寫入一些數據;此模式容許咱們進行讀取和寫入,若是文檔存在,此模式會初始化文檔並將其清空。在寫入一些數據以後,咱們找到文件的起始位置,讀取內容。代碼以下:

>>> recods=[bytes([char]*8) for char in b'spam']
>>> recods
[b'ssssssss', b'pppppppp', b'aaaaaaaa', b'mmmmmmmm']
>>> file=open('random.bin','wb+')
>>> for rec in recods:
...   size=file.write(rec)
... 
>>> file.flush()
>>> pos=file.seek(0)
>>> print(file.read())
b'ssssssssppppppppaaaaaaaammmmmmmm'

如今再在rb+模式下從新打開文件(該模式也容許讀和寫,但初始不清除文檔) 代碼以下:

 
>>> file=open('random.bin','rb+')
>>> print(file.read())
b'ssssssssppppppppaaaaaaaammmmmmmm'
>>> recod=b'X'*8
>>> file.seek(0)
0
>>> file.write(recod)            #更新第一條記錄
8
>>> file.seek(len(recod)*2)      #更新第三條記錄
16
>>> file.write(b'Y'*8)
8
>>> file.seek(8)
8
>>> file.read(len(recod))          #抓取第二條記錄
b'pppppppp'
>>> file.read(len(recod))          #抓取下一條記錄
b'YYYYYYYY'
>>> file.seek(0)
0
>>> file.read()                       #讀取整個文件
b'XXXXXXXXppppppppYYYYYYYYmmmmmmmm'
>>> exit()
[root@TrackerServer ~]# cat random.bin            #shell命令行查看文本
XXXXXXXXppppppppYYYYYYYYmmmmmmmm


若是使用尋找功能,通常來講不該該使用文本模式,換行符 unicode均可以進行任意轉換,兩者都使絕對尋找偏移變量難以使用。以下代碼:

>>> data='sp\xe4m'
>>> data,len(data)
('späm', 4)
>>> data.encode('utf8'), len(data.encode('utf8'))
(b'sp\xc3\xa4m', 5)
>>> f=open('test',mode='w+',encoding='utf8')
>>> f.write(data)
4
>>> f.flush()
>>> f.seek(0);f.read(1)
0
's'
>>> f.seek(2);f.read(1)
2
'ä'
>>> data[3]
'm'
>>> f.seek(3);f.read(1)
3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/python3.5/lib/python3.5/codecs.py", line 321, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa4 in position 0: invalid start byte


OS模塊的底層文件工具

os模塊包含了一個文件處理函數的附加集合:

os.open(path,flags,mode)

    打開文件並返回其描述符‘

os.read(descripter,N)

    最多讀取N個字節並返回一個字節字符串

os.write(descripter,string)

    把字節字符串string中的字節寫入文件

os.lseek(descripter,position,how)

    在文件中移動至positiong


嚴格地說os調用經過文件描述符來處理文件,基於描述符的文件以原始字節形式進行處理。除了緩衝等額外性能基於描述的文件通常都能對應上二進制模式文件對象,與文件對象相比,它更底層更復雜。

相關文章
相關標籤/搜索