python進階:第四章(文件I/O高效處理)

問題一:如何讀寫文本文件?

問題內(nèi)容:
某文件編碼格式已知(如UTF-8,GBK,BIG5),在python2.X和python3.X中分別如何讀取該文件?

解決方案:
我們首先明確下2到3的一些語義變化:
在python2中字符串有兩種形式:str和Unicode。str表面上抽象的是字符串,實際上抽象的是連續(xù)的字節(jié),對應python3中的bytes,只有這些字節(jié)存儲到物理設備上。而Unicode才是真正的字符串,對應python3中的str。

python2.x:寫入文件前對Unicode編碼,讀入文件后對二進制字符串解碼。
python3.x:open函數(shù)指定't'的文本模式,encoding指定編碼格式。

在python2下,我沒安裝python2,來看截圖吧:

Paste_Image.png

在python3中:

在python3中定義bytes需要前面加小 b ,而python2只要字節(jié)串。
In [1]: b'dfghjdfg'
Out[1]: b'dfghjdfg'
在python3中定義Unicode,前面不需要加小 u ,而python2中需要。
In [2]: '你好'
Out[2]: '你好'

文本文件的操作:

In [2]: f = open('py3.txt','wt',encoding='utf8')

In [3]: f.write('你好,我是王二小')
Out[3]: 8

In [4]: f.close()

In [5]: f = open('py3.txt','rt',encoding='utf8')

In [6]: s = f.read()

In [7]: print(s)
你好,我是王二小

文件寫入的時候是以字節(jié)寫入,不過編碼為了utf8,文件讀取的時候也是轉(zhuǎn)碼為utf8。

問題二:如何處理二進制文件

這段后續(xù)補充

In [9]: f = open('syst.wav','rb')

In [10]: info  = f.read(44)

In [11]: info
Out[11]: b'RIFF\xf4\x04\x92\x02WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00D\xac\x00\x00\x10\xb1\x02\x00\x04\x00\x10\x00data\xd0\x04\x92\x02'

In [12]: import struct

In [13]: struct.unpack?
Docstring:
unpack(fmt, buffer) -> (v1, v2, ...)

Return a tuple containing values unpacked according to the format string
fmt.  The buffer's size in bytes must be calcsize(fmt). See help(struct)
for more on format strings.
Type:      builtin_function_or_method

In [14]: struct.unpack('h','\x01\x02')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-14-4b76b634ada8> in <module>()
----> 1 struct.unpack('h','\x01\x02')

TypeError: a bytes-like object is required, not 'str'

In [15]: struct.unpack('h',info[22:24])
Out[15]: (2,)

In [16]: struct.unpack('i',info[24:28])
Out[16]: (44100,)

問題三:如何設置文件緩沖

問題內(nèi)容:
將文件內(nèi)容寫入到硬件設備時,使用系統(tǒng)調(diào)用,這類I/O操作的時間很長。為了減少I/O操作的次數(shù),文件通常使用緩沖區(qū)。(有足夠多的數(shù)據(jù)才進行系統(tǒng)調(diào)用)文件的緩沖行為,分為全緩沖,行緩沖,無緩沖。如何沒有緩沖會造成資源的浪費(未寫滿一個塊,依舊寫入,使用緩沖,只有當寫滿之后,才會插入)
如何設置python中文件的緩沖行為?

解決方案:
全緩沖:open函數(shù)的buffering設置為大于1的整數(shù)n,n為緩沖區(qū)大小
行緩沖:open函數(shù)的buffering設置為1
無緩沖:open函數(shù)的buffering設置為0

關于行緩沖:

In [29]: f = open('demo3.txt','w',buffering=1) 

In [30]: f.write('abcd') 
Out[30]: 4

In [31]: f.write('1234') 
Out[31]: 4

In [32]: f.write('\n') 
Out[32]: 1

我們使用tail 監(jiān)控輸入,只有我們輸入了 '\n'之后,數(shù)據(jù)才真正的寫入。
tail  -f  demo3.txt  
abcd1234

關于無緩沖:

In [36]: f = open('demo4.txt','w',buffering=0) 
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-36-7b816614dabf> in <module>()
----> 1 f = open('demo4.txt','w',buffering=0)

ValueError: can't have unbuffered text I/O

In [37]: f = open('demo4.txt','wb',buffering=0)

python3中文本文件不能設置buffering = 0,而二進制文件可以。

問題四:如何將文件映射到內(nèi)存?

問題內(nèi)容:
1,在訪問某些二進制文件時(通常使用read()和write()方法的時候,都是以流的形式讀寫,一個字節(jié)一個字節(jié)的順序進行),希望能把文件映射到內(nèi)存中,(像數(shù)組一樣訪問)可以實現(xiàn)隨機訪問。(framebuffer設備文件)

2,某些嵌入式設備,寄存器被編址到內(nèi)存地址空間,我們可以映射/dev/mem某范圍,去訪問這些寄存器。

3,如果多個進程映射同一個文件,還能實現(xiàn)進程通信的目的。

解決方案:
使用標準庫中mmap()函數(shù),它需要一個打開的文件描述符作為參數(shù)。

首先我們創(chuàng)建大小為1M,全部內(nèi)容為0的二進制文件。

dd  if=/dev/zero  of=demo.bin bs=1024 count=1024 

我們查看文件內(nèi)容:

od -x demo.bin 
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
4000000

我們查看下mmap函數(shù)的使用:

In [1]: import mmap 

In [2]: mmap.mmap 
Out[2]: mmap.mmap

In [3]: mmap.mmap?
Init signature: mmap.mmap(self, /, *args, **kwargs)
Docstring:     
Windows: mmap(fileno, length[, tagname[, access[, offset]]])

Maps length bytes from the file specified by the file handle fileno,
and returns a mmap object.  If length is larger than the current size
of the file, the file is extended to contain length bytes.  If length
is 0, the maximum length of the map is the current size of the file,
except that if the file is empty Windows raises an exception (you cannot
create an empty mapping on Windows).

Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])

Maps length bytes from the file specified by the file descriptor fileno,
and returns a mmap object.  If length is 0, the maximum length of the map
will be the current size of the file when mmap is called.
flags specifies the nature of the mapping. MAP_PRIVATE creates a
private copy-on-write mapping, so changes to the contents of the mmap
object will be private to this process, and MAP_SHARED creates a mapping
that's shared with all other processes mapping the same areas of the file.
The default value is MAP_SHARED.

To map anonymous memory, pass -1 as the fileno (both versions).
File:           /usr/local/lib/python3.5/lib-dynload/mmap.cpython-35m-x86_64-linux-gnu.so
Type:           type

函數(shù)的第一個參數(shù)為文件的描述符,由系統(tǒng)調(diào)用的open()函數(shù)產(chǎn)生。


In [4]: import os

In [5]: os.open?
Signature: os.open(path, flags, mode=511, *, dir_fd=None)
Docstring:
Open a file for low level IO.  Returns a file descriptor (integer).

If dir_fd is not None, it should be a file descriptor open to a directory,
  and path should be relative; path will then be relative to that directory.
dir_fd may not be implemented on your platform.
  If it is unavailable, using it will raise a NotImplementedError.
Type:      builtin_function_or_method

在這里我們使用python的open()函數(shù)和fileno()函數(shù)產(chǎn)生文件描述符:

In [7]: f = open("demo.bin",'r+b')

In [8]: f.fileno()
Out[8]: 11

函數(shù)的第二個參數(shù)是指映射大小,當為0的時候為全部映射。第三個參數(shù)為權限。

In [9]: mmap.mmap(f.fileno(),0,access=mmap.
                  mmap.ACCESS_COPY           mmap.MAP_ANONYMOUS         mmap.PAGESIZE              
                  mmap.ACCESS_READ           mmap.MAP_DENYWRITE         mmap.PROT_EXEC             
                  mmap.ACCESS_WRITE          mmap.MAP_EXECUTABLE        mmap.PROT_READ             
                  mmap.ALLOCATIONGRANULARITY mmap.MAP_PRIVATE           mmap.PROT_WRITE            
                  mmap.error                 mmap.MAP_SHARED                                       
                  mmap.MAP_ANON              mmap.mmap

以上為權限的列表。

In [9]: m = mmap.mmap(f.fileno(),0,access=mmap.ACCESS_WRITE)

In [10]: type(m) 
Out[10]: mmap.mmap

In [11]: m[0] 
Out[11]: 0

In [12]: m[10:20] 
Out[12]: b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

返回一個mmap對象,把內(nèi)存映射為一個數(shù)組,可以進行切片等操作。

問題五:如何訪問文件的狀態(tài)?

問題內(nèi)容:
1,文件的類型(普通文件,目錄,符號連接,設備文件。。。)
2,文件的訪問權限
3,文件的最后的訪問/修改/節(jié)點狀態(tài)更改時間
4,普通文件的大小

解決方法:
方法一:使用標準庫os模塊下的三個系統(tǒng)調(diào)用stat,fstat,lstat獲取文件狀態(tài)。
方法二:標準庫中os.path下一些函數(shù),使用起來更加簡潔

問題六:如何使用臨時文件?

問題內(nèi)容:
某項目,我們從傳感器采集數(shù)據(jù),每收集1G數(shù)據(jù)后,做數(shù)據(jù)分析,最終只保存分析結(jié)果。這樣很大的臨時數(shù)據(jù)如果常駐內(nèi)存,將消耗大量內(nèi)存資源,我們可以使用臨時文件存儲這些臨時數(shù)據(jù)(外部存儲)。
臨時文件不用命名,且關閉后會自動被刪除。

解決方案:
可以使用標準庫中tempfile下的temporaryFile,NamedTemporaryFile。

In [1]: from tempfile import TemporaryFile ,NamedTemporaryFile

In [2]: TemporaryFile?
Signature: TemporaryFile(mode='w+b', buffering=-1, encoding=None, newline=None, suffix=None, prefix=None, dir=None)
Docstring:
Create and return a temporary file.
Arguments:
'prefix', 'suffix', 'dir' -- as for mkstemp.
'mode' -- the mode argument to io.open (default "w+b").
'buffering' -- the buffer size argument to io.open (default -1).
'encoding' -- the encoding argument to io.open (default None)
'newline' -- the newline argument to io.open (default None)
The file is created as mkstemp() would do it.

Returns an object with a file-like interface.  The file has no
name, and will cease to exist when it is closed.
File:      /usr/local/lib/python3.5/tempfile.py
Type:      function

默認是以二進制打開文件的

In [3]: f = TemporaryFile('w+t') 

In [4]: f.write('abcdef' * 10000)
Out[4]: 60000

In [5]: f.seek(0) 
Out[5]: 0

In [6]: f.read(100) 
Out[6]: 'abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd'

使用TemporaryFile()創(chuàng)建的文件,不能在文件系統(tǒng)中查找到,只能通過文件對象 f 訪問。

使用NamedTemporaryFile()創(chuàng)建的臨時文件則可以在文件系統(tǒng)中查找得到。

In [7]: NamedTemporaryFile?
Signature: NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None, newline=None, suffix=None, prefix=None, dir=None, delete=True)
Docstring:
Create and return a temporary file.
Arguments:
'prefix', 'suffix', 'dir' -- as for mkstemp.
'mode' -- the mode argument to io.open (default "w+b").
'buffering' -- the buffer size argument to io.open (default -1).
'encoding' -- the encoding argument to io.open (default None)
'newline' -- the newline argument to io.open (default None)
'delete' -- whether the file is deleted on close (default True).
The file is created as mkstemp() would do it.

Returns an object with a file-like interface; the name of the file
is accessible as its 'name' attribute.  The file will be automatically
deleted when it is closed unless the 'delete' argument is set to False.
File:      /usr/local/lib/python3.5/tempfile.py
Type:      function

In [8]: ntf = NamedTemporaryFile("w+t") 

In [9]: ntf.
  File "<ipython-input-9-adee75e8b522>", line 1
    ntf.
        ^
SyntaxError: invalid syntax
In [10]: ntf.
              ntf.close  ntf.file   
              ntf.delete ntf.name 

In [10]: ntf.name
Out[10]: '/tmp/tmp7ggfe3br'
name屬性就是文件路徑

In [11]: ntf = NamedTemporaryFile("w+t") 

In [12]: ntf.name
Out[12]: '/tmp/tmp9gbuotxm'

我們發(fā)現(xiàn)兩次的name屬性值不同,是因為每次關閉之后,前面的文件會被刪除掉

我們可以指定Signature: NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None, newline=None, suffix=None, prefix=None, dir=None, delete=True)
函數(shù)參數(shù)里面的 delete= 為False。則關閉后之前的文件不會被刪除。

In [13]: ntf = NamedTemporaryFile("w+t", delete=False) 

In [14]: ntf.name 
Out[14]: '/tmp/tmpgfps1wco'

In [15]: ntf = NamedTemporaryFile("w+t", delete=False) 

In [16]: ntf.name 
Out[16]: '/tmp/tmpbm6a_0ze'

tmpbm6a_0ze
tmpgfps1wco

我們可以看到之前創(chuàng)建的tmpgfps1wco并沒有在文件關閉之后刪除。
使用NamedTemporaryFile()創(chuàng)建的文件可以被多個進程訪問,而被TemporaryFile()創(chuàng)建的文件只能被當前進程訪問。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 定義類并創(chuàng)建實例 在Python中,類通過 class 關鍵字定義。以 Person 為例,定義一個Person類...
    績重KF閱讀 4,097評論 0 13
  • 4.1 字符串的語義 在python2 和 python3中,對字符串的語義是有著很大的區(qū)別的。 python2s...
    Lemon_Home閱讀 610評論 0 0
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,534評論 19 139
  • 我有一輛單車 后車座空空蕩蕩 后車輪吱吱嘎嘎 不停轉(zhuǎn)動著寂寞 當我可以接你放學 便安了一個后車凳 車凳全是愛做的海...
    倫小讓閱讀 131評論 4 1
  • 看著自己在屏幕上敲下的文字,刪了又寫,寫了又刪。仿佛回到課堂上的無命題作文,給你足夠的自由盡情發(fā)揮,卻反而不知如何...
    文大人頻道閱讀 248評論 0 0

友情鏈接更多精彩內(nèi)容